Merge \"Make Settings->Apps can handle work apps even work profile not enabled yet\" into nyc-dev
am: 18c8690b7e

Change-Id: I8daa485fcf810c5c5bb40903216f8b989658b5ca
diff --git a/Android.mk b/Android.mk
index 76e9b33..044e45a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -695,6 +695,7 @@
 	frameworks/base/core/java/android/service/quicksettings/Tile.aidl \
 	frameworks/native/aidl/binder/android/os/PersistableBundle.aidl \
 	system/netd/server/binder/android/net/UidRange.aidl \
+	frameworks/base/telephony/java/android/telephony/PcoData.aidl \
 
 gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
 $(gen): PRIVATE_SRC_FILES := $(aidl_files)
diff --git a/api/current.txt b/api/current.txt
index 3bd607b..83f6131 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -420,7 +420,9 @@
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
     field public static final int contextClickable = 16844007; // 0x10104e7
+    field public static final int contextDescription = 16844082; // 0x1010532
     field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+    field public static final int contextUri = 16844081; // 0x1010531
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1039,6 +1041,7 @@
     field public static final int rotation = 16843558; // 0x1010326
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
+    field public static final int roundIcon = 16844080; // 0x1010530
     field public static final int rowCount = 16843637; // 0x1010375
     field public static final int rowDelay = 16843216; // 0x10101d0
     field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1106,11 +1109,20 @@
     field public static final int shareInterpolator = 16843195; // 0x10101bb
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
+    field public static final int shortcutCategories = 16844077; // 0x101052d
+    field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
+    field public static final int shortcutIcon = 16844073; // 0x1010529
+    field public static final int shortcutId = 16844072; // 0x1010528
+    field public static final int shortcutIntentAction = 16844078; // 0x101052e
+    field public static final int shortcutIntentData = 16844079; // 0x101052f
+    field public static final int shortcutLongLabel = 16844075; // 0x101052b
+    field public static final int shortcutShortLabel = 16844074; // 0x101052a
     field public static final int shouldDisableView = 16843246; // 0x10101ee
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
+    field public static final int showMetadataInPreview = 16844083; // 0x1010533
     field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
@@ -5756,7 +5768,10 @@
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public java.lang.String getServiceName();
     method public java.lang.String getSettingsActivity();
+    method public boolean getShowMetadataInPreview();
     method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6484,11 +6499,13 @@
     method public android.content.res.Configuration getConfiguration();
     method public int getEventType();
     method public java.lang.String getPackageName();
+    method public java.lang.String getShortcutId();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SHORTCUT_INVOCATION = 8; // 0x8
     field public static final int USER_INTERACTION = 7; // 0x7
   }
 
@@ -8191,6 +8208,7 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9500,13 +9518,22 @@
 
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+    method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9519,6 +9546,20 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+    method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+    method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+    method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_MANIFEST = 8; // 0x8
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -10019,6 +10060,86 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivity();
+    method public java.util.Set<java.lang.String> getCategories();
+    method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledMessageResourceId();
+    method public android.os.PersistableBundle getExtras();
+    method public int getIconResourceId();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.CharSequence getLongLabel();
+    method public int getLongLabelResourceId();
+    method public java.lang.String getPackage();
+    method public int getRank();
+    method public java.lang.CharSequence getShortLabel();
+    method public int getShortLabelResourceId();
+    method public android.os.UserHandle getUserHandle();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean hasStringResourcesResolved();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isManifestShortcut();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DISABLED = 64; // 0x40
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_IMMUTABLE = 256; // 0x100
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_MANIFEST = 32; // 0x20
+    field public static final int FLAG_PINNED = 2; // 0x2
+    field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
+    field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setRank(int);
+    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+  }
+
+  public class ShortcutManager {
+    method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public void disableShortcuts(java.util.List<java.lang.String>);
+    method public void disableShortcuts(java.util.List<java.lang.String>, int);
+    method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
+    method public void enableShortcuts(java.util.List<java.lang.String>);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxHeight();
+    method public int getIconMaxWidth();
+    method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
+    method public int getMaxShortcutCountForActivity();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public void removeAllDynamicShortcuts();
+    method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
+    method public void reportShortcutUsed(java.lang.String);
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -30640,6 +30761,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30662,6 +30784,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -32281,6 +32404,7 @@
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
+    field public static final java.lang.String ACTION_DELETION_HELPER_SETTINGS = "android.settings.DELETION_HELPER_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
@@ -32984,6 +33108,7 @@
     field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+    field public static final java.lang.String SOURCE_TYPE = "source_type";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
   }
 
@@ -35936,9 +36061,14 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -35952,6 +36082,7 @@
     field public static final int STATE_DISCONNECTING = 10; // 0xa
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -35962,6 +36093,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -35992,6 +36124,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -36011,7 +36144,9 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
 
@@ -36062,6 +36197,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36074,6 +36210,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -36082,14 +36219,18 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -36115,6 +36256,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -36125,16 +36267,24 @@
     method public void onAnswer(int);
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -36142,9 +36292,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -36158,6 +36309,7 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
     field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36175,15 +36327,19 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -36261,7 +36417,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -36297,6 +36455,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
@@ -36419,6 +36578,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36437,6 +36597,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -36448,6 +36609,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -36464,6 +36626,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36560,6 +36724,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -37200,6 +37365,26 @@
     method public void onSubscriptionsChanged();
   }
 
+  public final class TelephonyHistogram implements android.os.Parcelable {
+    ctor public TelephonyHistogram(int, int, int);
+    ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
+    ctor public TelephonyHistogram(android.os.Parcel);
+    method public void addTimeTaken(int);
+    method public int describeContents();
+    method public int getAverageTime();
+    method public int getBucketCount();
+    method public int[] getBucketCounters();
+    method public int[] getBucketEndPoints();
+    method public int getCategory();
+    method public int getId();
+    method public int getMaxTime();
+    method public int getMinTime();
+    method public int getSampleCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.TelephonyHistogram> CREATOR;
+    field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1
+  }
+
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
@@ -37230,6 +37415,7 @@
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -41304,6 +41490,10 @@
     field public static final int KEYCODE_FOCUS = 80; // 0x50
     field public static final int KEYCODE_FORWARD = 125; // 0x7d
     field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
+    field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
+    field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
+    field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
+    field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
     field public static final int KEYCODE_FUNCTION = 119; // 0x77
     field public static final int KEYCODE_G = 35; // 0x23
     field public static final int KEYCODE_GRAVE = 68; // 0x44
diff --git a/api/system-current.txt b/api/system-current.txt
index 3a2f29b..e2a0516 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -526,7 +526,9 @@
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
     field public static final int contextClickable = 16844007; // 0x10104e7
+    field public static final int contextDescription = 16844082; // 0x1010532
     field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+    field public static final int contextUri = 16844081; // 0x1010531
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1145,6 +1147,7 @@
     field public static final int rotation = 16843558; // 0x1010326
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
+    field public static final int roundIcon = 16844080; // 0x1010530
     field public static final int rowCount = 16843637; // 0x1010375
     field public static final int rowDelay = 16843216; // 0x10101d0
     field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1216,11 +1219,20 @@
     field public static final int shareInterpolator = 16843195; // 0x10101bb
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
+    field public static final int shortcutCategories = 16844077; // 0x101052d
+    field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
+    field public static final int shortcutIcon = 16844073; // 0x1010529
+    field public static final int shortcutId = 16844072; // 0x1010528
+    field public static final int shortcutIntentAction = 16844078; // 0x101052e
+    field public static final int shortcutIntentData = 16844079; // 0x101052f
+    field public static final int shortcutLongLabel = 16844075; // 0x101052b
+    field public static final int shortcutShortLabel = 16844074; // 0x101052a
     field public static final int shouldDisableView = 16843246; // 0x10101ee
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
+    field public static final int showMetadataInPreview = 16844083; // 0x1010533
     field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
@@ -5903,7 +5915,10 @@
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public java.lang.String getServiceName();
     method public java.lang.String getSettingsActivity();
+    method public boolean getShowMetadataInPreview();
     method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6765,11 +6780,13 @@
     method public android.content.res.Configuration getConfiguration();
     method public int getEventType();
     method public java.lang.String getPackageName();
+    method public java.lang.String getShortcutId();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SHORTCUT_INVOCATION = 8; // 0x8
     field public static final int USER_INTERACTION = 7; // 0x7
   }
 
@@ -8513,6 +8530,7 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9853,13 +9871,22 @@
 
   public class LauncherApps {
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+    method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9872,6 +9899,20 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+    method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+    method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+    method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_MANIFEST = 8; // 0x8
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -10442,6 +10483,86 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivity();
+    method public java.util.Set<java.lang.String> getCategories();
+    method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledMessageResourceId();
+    method public android.os.PersistableBundle getExtras();
+    method public int getIconResourceId();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.CharSequence getLongLabel();
+    method public int getLongLabelResourceId();
+    method public java.lang.String getPackage();
+    method public int getRank();
+    method public java.lang.CharSequence getShortLabel();
+    method public int getShortLabelResourceId();
+    method public android.os.UserHandle getUserHandle();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean hasStringResourcesResolved();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isManifestShortcut();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DISABLED = 64; // 0x40
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_IMMUTABLE = 256; // 0x100
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_MANIFEST = 32; // 0x20
+    field public static final int FLAG_PINNED = 2; // 0x2
+    field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
+    field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setRank(int);
+    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+  }
+
+  public class ShortcutManager {
+    method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public void disableShortcuts(java.util.List<java.lang.String>);
+    method public void disableShortcuts(java.util.List<java.lang.String>, int);
+    method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
+    method public void enableShortcuts(java.util.List<java.lang.String>);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxHeight();
+    method public int getIconMaxWidth();
+    method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
+    method public int getMaxShortcutCountForActivity();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public void removeAllDynamicShortcuts();
+    method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
+    method public void reportShortcutUsed(java.lang.String);
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -33211,6 +33332,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -33233,6 +33355,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -34984,6 +35107,7 @@
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
+    field public static final java.lang.String ACTION_DELETION_HELPER_SETTINGS = "android.settings.DELETION_HELPER_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
@@ -35690,6 +35814,7 @@
     field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+    field public static final java.lang.String SOURCE_TYPE = "source_type";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
   }
 
@@ -38770,10 +38895,15 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
     method public deprecated void removeListener(android.telecom.Call.Listener);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -38788,6 +38918,7 @@
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
     field public static final deprecated int STATE_PRE_DIAL_WAIT = 8; // 0x8
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -38798,6 +38929,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -38828,6 +38960,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -38847,7 +38980,9 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
 
@@ -38904,6 +39039,7 @@
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final deprecated long getConnectTimeMillis();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -38918,6 +39054,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -38926,15 +39063,19 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final deprecated void setConnectTimeMillis(long);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -38961,6 +39102,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -38972,16 +39114,24 @@
     method public void onAnswer();
     method public deprecated void onAudioStateChanged(android.telecom.AudioState);
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -38989,9 +39139,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -39005,6 +39156,7 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
     field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -39022,15 +39174,19 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -39108,7 +39264,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -39145,6 +39303,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public deprecated void onPhoneCreated(android.telecom.Phone);
     method public deprecated void onPhoneDestroyed(android.telecom.Phone);
     method public void onSilenceRinger();
@@ -39322,6 +39481,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -39340,6 +39500,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -39351,6 +39512,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -39368,6 +39530,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -39491,6 +39655,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -40133,6 +40298,26 @@
     method public void onSubscriptionsChanged();
   }
 
+  public final class TelephonyHistogram implements android.os.Parcelable {
+    ctor public TelephonyHistogram(int, int, int);
+    ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
+    ctor public TelephonyHistogram(android.os.Parcel);
+    method public void addTimeTaken(int);
+    method public int describeContents();
+    method public int getAverageTime();
+    method public int getBucketCount();
+    method public int[] getBucketCounters();
+    method public int[] getBucketEndPoints();
+    method public int getCategory();
+    method public int getId();
+    method public int getMaxTime();
+    method public int getMinTime();
+    method public int getSampleCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.TelephonyHistogram> CREATOR;
+    field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1
+  }
+
   public class TelephonyManager {
     method public void answerRingingCall();
     method public void call(java.lang.String, java.lang.String);
@@ -40182,6 +40367,7 @@
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -44302,6 +44488,10 @@
     field public static final int KEYCODE_FOCUS = 80; // 0x50
     field public static final int KEYCODE_FORWARD = 125; // 0x7d
     field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
+    field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
+    field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
+    field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
+    field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
     field public static final int KEYCODE_FUNCTION = 119; // 0x77
     field public static final int KEYCODE_G = 35; // 0x23
     field public static final int KEYCODE_GRAVE = 68; // 0x44
diff --git a/api/test-current.txt b/api/test-current.txt
index 8425e90..e74b845 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -420,7 +420,9 @@
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contentInsetStartWithNavigation = 16844066; // 0x1010522
     field public static final int contextClickable = 16844007; // 0x10104e7
+    field public static final int contextDescription = 16844082; // 0x1010532
     field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+    field public static final int contextUri = 16844081; // 0x1010531
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1039,6 +1041,7 @@
     field public static final int rotation = 16843558; // 0x1010326
     field public static final int rotationX = 16843559; // 0x1010327
     field public static final int rotationY = 16843560; // 0x1010328
+    field public static final int roundIcon = 16844080; // 0x1010530
     field public static final int rowCount = 16843637; // 0x1010375
     field public static final int rowDelay = 16843216; // 0x10101d0
     field public static final int rowEdgeFlags = 16843329; // 0x1010241
@@ -1106,11 +1109,20 @@
     field public static final int shareInterpolator = 16843195; // 0x10101bb
     field public static final int sharedUserId = 16842763; // 0x101000b
     field public static final int sharedUserLabel = 16843361; // 0x1010261
+    field public static final int shortcutCategories = 16844077; // 0x101052d
+    field public static final int shortcutDisabledMessage = 16844076; // 0x101052c
+    field public static final int shortcutIcon = 16844073; // 0x1010529
+    field public static final int shortcutId = 16844072; // 0x1010528
+    field public static final int shortcutIntentAction = 16844078; // 0x101052e
+    field public static final int shortcutIntentData = 16844079; // 0x101052f
+    field public static final int shortcutLongLabel = 16844075; // 0x101052b
+    field public static final int shortcutShortLabel = 16844074; // 0x101052a
     field public static final int shouldDisableView = 16843246; // 0x10101ee
     field public static final int showAsAction = 16843481; // 0x10102d9
     field public static final int showDefault = 16843258; // 0x10101fa
     field public static final int showDividers = 16843561; // 0x1010329
     field public static final int showForAllUsers = 16844015; // 0x10104ef
+    field public static final int showMetadataInPreview = 16844083; // 0x1010533
     field public static final deprecated int showOnLockScreen = 16843721; // 0x10103c9
     field public static final int showSilent = 16843259; // 0x10101fb
     field public static final int showText = 16843949; // 0x10104ad
@@ -5762,7 +5774,10 @@
     method public android.content.pm.ServiceInfo getServiceInfo();
     method public java.lang.String getServiceName();
     method public java.lang.String getSettingsActivity();
+    method public boolean getShowMetadataInPreview();
     method public java.lang.CharSequence loadAuthor(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public java.lang.CharSequence loadContextDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
+    method public android.net.Uri loadContextUri(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
@@ -6490,11 +6505,13 @@
     method public android.content.res.Configuration getConfiguration();
     method public int getEventType();
     method public java.lang.String getPackageName();
+    method public java.lang.String getShortcutId();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
+    field public static final int SHORTCUT_INVOCATION = 8; // 0x8
     field public static final int USER_INTERACTION = 7; // 0x7
   }
 
@@ -8199,6 +8216,7 @@
     field public static final java.lang.String RESTRICTIONS_SERVICE = "restrictions";
     field public static final java.lang.String SEARCH_SERVICE = "search";
     field public static final java.lang.String SENSOR_SERVICE = "sensor";
+    field public static final java.lang.String SHORTCUT_SERVICE = "shortcut";
     field public static final java.lang.String STORAGE_SERVICE = "storage";
     field public static final java.lang.String SYSTEM_HEALTH_SERVICE = "systemhealth";
     field public static final java.lang.String TELECOM_SERVICE = "telecom";
@@ -9512,13 +9530,22 @@
   public class LauncherApps {
     ctor public LauncherApps(android.content.Context);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
+    method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(android.content.pm.ShortcutInfo);
+    method public android.os.ParcelFileDescriptor getShortcutIconFd(java.lang.String, java.lang.String, android.os.UserHandle);
+    method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
+    method public boolean hasShortcutHostPermission();
     method public boolean isActivityEnabled(android.content.ComponentName, android.os.UserHandle);
     method public boolean isPackageEnabled(java.lang.String, android.os.UserHandle);
+    method public void pinShortcuts(java.lang.String, java.util.List<java.lang.String>, android.os.UserHandle);
     method public void registerCallback(android.content.pm.LauncherApps.Callback);
     method public void registerCallback(android.content.pm.LauncherApps.Callback, android.os.Handler);
     method public android.content.pm.LauncherActivityInfo resolveActivity(android.content.Intent, android.os.UserHandle);
     method public void startAppDetailsActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
     method public void startMainActivity(android.content.ComponentName, android.os.UserHandle, android.graphics.Rect, android.os.Bundle);
+    method public boolean startShortcut(java.lang.String, java.lang.String, android.graphics.Rect, android.os.Bundle, android.os.UserHandle);
+    method public boolean startShortcut(android.content.pm.ShortcutInfo, android.graphics.Rect, android.os.Bundle);
     method public void unregisterCallback(android.content.pm.LauncherApps.Callback);
   }
 
@@ -9531,6 +9558,20 @@
     method public void onPackagesSuspended(java.lang.String[], android.os.UserHandle);
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
     method public void onPackagesUnsuspended(java.lang.String[], android.os.UserHandle);
+    method public void onShortcutsChanged(java.lang.String, java.util.List<android.content.pm.ShortcutInfo>, android.os.UserHandle);
+  }
+
+  public static class LauncherApps.ShortcutQuery {
+    ctor public LauncherApps.ShortcutQuery();
+    method public android.content.pm.LauncherApps.ShortcutQuery setActivity(android.content.ComponentName);
+    method public android.content.pm.LauncherApps.ShortcutQuery setChangedSince(long);
+    method public android.content.pm.LauncherApps.ShortcutQuery setPackage(java.lang.String);
+    method public android.content.pm.LauncherApps.ShortcutQuery setQueryFlags(int);
+    method public android.content.pm.LauncherApps.ShortcutQuery setShortcutIds(java.util.List<java.lang.String>);
+    field public static final int FLAG_GET_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_GET_KEY_FIELDS_ONLY = 4; // 0x4
+    field public static final int FLAG_GET_MANIFEST = 8; // 0x8
+    field public static final int FLAG_GET_PINNED = 2; // 0x2
   }
 
   public class PackageInfo implements android.os.Parcelable {
@@ -10032,6 +10073,87 @@
     field public java.lang.String permission;
   }
 
+  public final class ShortcutInfo implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.content.ComponentName getActivity();
+    method public java.util.Set<java.lang.String> getCategories();
+    method public java.lang.CharSequence getDisabledMessage();
+    method public int getDisabledMessageResourceId();
+    method public android.os.PersistableBundle getExtras();
+    method public int getIconResourceId();
+    method public java.lang.String getId();
+    method public android.content.Intent getIntent();
+    method public long getLastChangedTimestamp();
+    method public java.lang.CharSequence getLongLabel();
+    method public int getLongLabelResourceId();
+    method public java.lang.String getPackage();
+    method public int getRank();
+    method public java.lang.CharSequence getShortLabel();
+    method public int getShortLabelResourceId();
+    method public android.os.UserHandle getUserHandle();
+    method public boolean hasIconFile();
+    method public boolean hasIconResource();
+    method public boolean hasKeyFieldsOnly();
+    method public boolean hasStringResourcesResolved();
+    method public boolean isDynamic();
+    method public boolean isEnabled();
+    method public boolean isImmutable();
+    method public boolean isManifestShortcut();
+    method public boolean isPinned();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int CLONE_REMOVE_FOR_CREATOR = 1; // 0x1
+    field public static final int CLONE_REMOVE_FOR_LAUNCHER = 3; // 0x3
+    field public static final int CLONE_REMOVE_NON_KEY_INFO = 4; // 0x4
+    field public static final android.os.Parcelable.Creator<android.content.pm.ShortcutInfo> CREATOR;
+    field public static final int FLAG_DISABLED = 64; // 0x40
+    field public static final int FLAG_DYNAMIC = 1; // 0x1
+    field public static final int FLAG_HAS_ICON_FILE = 8; // 0x8
+    field public static final int FLAG_HAS_ICON_RES = 4; // 0x4
+    field public static final int FLAG_IMMUTABLE = 256; // 0x100
+    field public static final int FLAG_KEY_FIELDS_ONLY = 16; // 0x10
+    field public static final int FLAG_MANIFEST = 32; // 0x20
+    field public static final int FLAG_PINNED = 2; // 0x2
+    field public static final int FLAG_STRINGS_RESOLVED = 128; // 0x80
+    field public static final java.lang.String SHORTCUT_CATEGORY_CONVERSATION = "android.shortcut.conversation";
+  }
+
+  public static class ShortcutInfo.Builder {
+    ctor public ShortcutInfo.Builder(android.content.Context);
+    method public android.content.pm.ShortcutInfo build();
+    method public android.content.pm.ShortcutInfo.Builder setActivity(android.content.ComponentName);
+    method public android.content.pm.ShortcutInfo.Builder setCategories(java.util.Set<java.lang.String>);
+    method public android.content.pm.ShortcutInfo.Builder setDisabledMessage(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setExtras(android.os.PersistableBundle);
+    method public android.content.pm.ShortcutInfo.Builder setIcon(android.graphics.drawable.Icon);
+    method public android.content.pm.ShortcutInfo.Builder setId(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setIntent(android.content.Intent);
+    method public android.content.pm.ShortcutInfo.Builder setLongLabel(java.lang.String);
+    method public android.content.pm.ShortcutInfo.Builder setRank(int);
+    method public android.content.pm.ShortcutInfo.Builder setShortLabel(java.lang.String);
+  }
+
+  public class ShortcutManager {
+    ctor public ShortcutManager(android.content.Context);
+    method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public void disableShortcuts(java.util.List<java.lang.String>);
+    method public void disableShortcuts(java.util.List<java.lang.String>, int);
+    method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.String);
+    method public void enableShortcuts(java.util.List<java.lang.String>);
+    method public java.util.List<android.content.pm.ShortcutInfo> getDynamicShortcuts();
+    method public int getIconMaxHeight();
+    method public int getIconMaxWidth();
+    method public java.util.List<android.content.pm.ShortcutInfo> getManifestShortcuts();
+    method public int getMaxShortcutCountForActivity();
+    method public java.util.List<android.content.pm.ShortcutInfo> getPinnedShortcuts();
+    method public long getRateLimitResetTime();
+    method public int getRemainingCallCount();
+    method public void removeAllDynamicShortcuts();
+    method public void removeDynamicShortcuts(java.util.List<java.lang.String>);
+    method public void reportShortcutUsed(java.lang.String);
+    method public boolean setDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public boolean updateShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+  }
+
   public class Signature implements android.os.Parcelable {
     ctor public Signature(byte[]);
     ctor public Signature(java.lang.String);
@@ -30713,6 +30835,7 @@
   public static class CallLog.Calls implements android.provider.BaseColumns {
     ctor public CallLog.Calls();
     method public static java.lang.String getLastOutgoingCall(android.content.Context);
+    field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7
     field public static final int BLOCKED_TYPE = 6; // 0x6
     field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number";
     field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri";
@@ -30735,6 +30858,7 @@
     field public static final java.lang.String DURATION = "duration";
     field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
     field public static final java.lang.String FEATURES = "features";
+    field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2
     field public static final int FEATURES_VIDEO = 1; // 0x1
     field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location";
     field public static final int INCOMING_TYPE = 1; // 0x1
@@ -32354,6 +32478,7 @@
     field public static final java.lang.String ACTION_CAST_SETTINGS = "android.settings.CAST_SETTINGS";
     field public static final java.lang.String ACTION_DATA_ROAMING_SETTINGS = "android.settings.DATA_ROAMING_SETTINGS";
     field public static final java.lang.String ACTION_DATE_SETTINGS = "android.settings.DATE_SETTINGS";
+    field public static final java.lang.String ACTION_DELETION_HELPER_SETTINGS = "android.settings.DELETION_HELPER_SETTINGS";
     field public static final java.lang.String ACTION_DEVICE_INFO_SETTINGS = "android.settings.DEVICE_INFO_SETTINGS";
     field public static final java.lang.String ACTION_DISPLAY_SETTINGS = "android.settings.DISPLAY_SETTINGS";
     field public static final java.lang.String ACTION_DREAM_SETTINGS = "android.settings.DREAM_SETTINGS";
@@ -33060,6 +33185,7 @@
     field public static final int QUOTA_UNAVAILABLE = -1; // 0xffffffff
     field public static final java.lang.String SETTINGS_URI = "settings_uri";
     field public static final java.lang.String SOURCE_PACKAGE = "source_package";
+    field public static final java.lang.String SOURCE_TYPE = "source_type";
     field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
   }
 
@@ -36013,9 +36139,14 @@
     method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
+    method public final void putExtras(android.os.Bundle);
     method public void registerCallback(android.telecom.Call.Callback);
     method public void registerCallback(android.telecom.Call.Callback, android.os.Handler);
     method public void reject(boolean, java.lang.String);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
+    method public void sendCallEvent(java.lang.String, android.os.Bundle);
     method public void splitFromConference();
     method public void stopDtmfTone();
     method public void swapConference();
@@ -36029,6 +36160,7 @@
     field public static final int STATE_DISCONNECTING = 10; // 0xa
     field public static final int STATE_HOLDING = 3; // 0x3
     field public static final int STATE_NEW = 0; // 0x0
+    field public static final int STATE_PULLING_CALL = 11; // 0xb
     field public static final int STATE_RINGING = 2; // 0x2
     field public static final int STATE_SELECT_PHONE_ACCOUNT = 8; // 0x8
   }
@@ -36039,6 +36171,7 @@
     method public void onCannedTextResponsesLoaded(android.telecom.Call, java.util.List<java.lang.String>);
     method public void onChildrenChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
     method public void onConferenceableCallsChanged(android.telecom.Call, java.util.List<android.telecom.Call>);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
     method public void onParentChanged(android.telecom.Call, android.telecom.Call);
     method public void onPostDialWait(android.telecom.Call, java.lang.String);
@@ -36069,6 +36202,7 @@
     method public static java.lang.String propertiesToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 8388608; // 0x800000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
     field public static final int CAPABILITY_MANAGE_CONFERENCE = 128; // 0x80
@@ -36088,7 +36222,9 @@
     field public static final int PROPERTY_EMERGENCY_CALLBACK_MODE = 4; // 0x4
     field public static final int PROPERTY_ENTERPRISE_CALL = 32; // 0x20
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
 
@@ -36139,6 +36275,7 @@
     method public final android.telecom.CallAudioState getCallAudioState();
     method public final java.util.List<android.telecom.Connection> getConferenceableConnections();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final long getConnectionTime();
     method public final java.util.List<android.telecom.Connection> getConnections();
     method public final android.telecom.DisconnectCause getDisconnectCause();
@@ -36151,6 +36288,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onConnectionAdded(android.telecom.Connection);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onMerge(android.telecom.Connection);
     method public void onMerge();
@@ -36159,14 +36297,18 @@
     method public void onStopDtmfTone();
     method public void onSwap();
     method public void onUnhold();
+    method public final void putExtras(android.os.Bundle);
     method public final void removeConnection(android.telecom.Connection);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
     method public final void setActive();
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setConnectionTime(long);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setOnHold();
     method public final void setStatusHints(android.telecom.StatusHints);
     method public final void setVideoProvider(android.telecom.Connection, android.telecom.Connection.VideoProvider);
@@ -36192,6 +36334,7 @@
     method public final android.telecom.Conference getConference();
     method public final java.util.List<android.telecom.Conferenceable> getConferenceables();
     method public final int getConnectionCapabilities();
+    method public final int getConnectionProperties();
     method public final android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public final int getState();
@@ -36202,16 +36345,24 @@
     method public void onAnswer(int);
     method public void onAnswer();
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
+    method public void onCallEvent(java.lang.String, android.os.Bundle);
     method public void onDisconnect();
+    method public void onExtrasChanged(android.os.Bundle);
     method public void onHold();
     method public void onPlayDtmfTone(char);
     method public void onPostDialContinue(boolean);
+    method public void onPullExternalCall();
     method public void onReject();
     method public void onReject(java.lang.String);
     method public void onSeparate();
     method public void onStateChanged(int);
     method public void onStopDtmfTone();
     method public void onUnhold();
+    method public static java.lang.String propertiesToString(int);
+    method public final void putExtras(android.os.Bundle);
+    method public final void removeExtras(java.util.List<java.lang.String>);
+    method public final void removeExtras(java.lang.String...);
+    method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
     method public final void setActive();
     method public final void setAddress(android.net.Uri, int);
     method public final void setAudioModeIsVoip(boolean);
@@ -36219,9 +36370,10 @@
     method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>);
     method public final void setConferenceables(java.util.List<android.telecom.Conferenceable>);
     method public final void setConnectionCapabilities(int);
+    method public final void setConnectionProperties(int);
     method public final void setDialing();
     method public final void setDisconnected(android.telecom.DisconnectCause);
-    method public final void setExtras(android.os.Bundle);
+    method public final deprecated void setExtras(android.os.Bundle);
     method public final void setInitialized();
     method public final void setInitializing();
     method public final void setNextPostDialChar(char);
@@ -36235,6 +36387,7 @@
     method public static java.lang.String stateToString(int);
     field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
+    field public static final int CAPABILITY_CAN_PULL_CALL = 16777216; // 0x1000000
     field public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -36252,15 +36405,19 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
     field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
+    field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
+    field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
     field public static final int STATE_ACTIVE = 4; // 0x4
     field public static final int STATE_DIALING = 3; // 0x3
     field public static final int STATE_DISCONNECTED = 6; // 0x6
     field public static final int STATE_HOLDING = 5; // 0x5
     field public static final int STATE_INITIALIZING = 0; // 0x0
     field public static final int STATE_NEW = 1; // 0x1
+    field public static final int STATE_PULLING_CALL = 7; // 0x7
     field public static final int STATE_RINGING = 2; // 0x2
   }
 
@@ -36338,7 +36495,9 @@
     method public java.lang.String getReason();
     method public int getTone();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ANSWERED_ELSEWHERE = 11; // 0xb
     field public static final int BUSY = 7; // 0x7
+    field public static final int CALL_PULLED = 12; // 0xc
     field public static final int CANCELED = 4; // 0x4
     field public static final int CONNECTION_MANAGER_NOT_SUPPORTED = 10; // 0xa
     field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR;
@@ -36374,6 +36533,7 @@
     method public void onCallAudioStateChanged(android.telecom.CallAudioState);
     method public void onCallRemoved(android.telecom.Call);
     method public void onCanAddCallChanged(boolean);
+    method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
     method public void onSilenceRinger();
     method public final void setAudioRoute(int);
     method public final void setMuted(boolean);
@@ -36496,6 +36656,7 @@
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConference, int);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConference, int);
     method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection);
     method public void onDestroyed(android.telecom.RemoteConference);
     method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause);
@@ -36514,6 +36675,7 @@
     method public android.telecom.RemoteConference getConference();
     method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections();
     method public int getConnectionCapabilities();
+    method public int getConnectionProperties();
     method public android.telecom.DisconnectCause getDisconnectCause();
     method public final android.os.Bundle getExtras();
     method public int getState();
@@ -36525,6 +36687,7 @@
     method public boolean isVoipAudioMode();
     method public void playDtmfTone(char);
     method public void postDialContinue(boolean);
+    method public void pullExternalCall();
     method public void registerCallback(android.telecom.RemoteConnection.Callback);
     method public void registerCallback(android.telecom.RemoteConnection.Callback, android.os.Handler);
     method public void reject();
@@ -36541,6 +36704,8 @@
     method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference);
     method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>);
     method public void onConnectionCapabilitiesChanged(android.telecom.RemoteConnection, int);
+    method public void onConnectionEvent(android.telecom.RemoteConnection, java.lang.String, android.os.Bundle);
+    method public void onConnectionPropertiesChanged(android.telecom.RemoteConnection, int);
     method public void onDestroyed(android.telecom.RemoteConnection);
     method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause);
     method public void onExtrasChanged(android.telecom.RemoteConnection, android.os.Bundle);
@@ -36637,6 +36802,7 @@
     field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
     field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
     field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
+    field public static final java.lang.String METADATA_INCLUDE_EXTERNAL_CALLS = "android.telecom.INCLUDE_EXTERNAL_CALLS";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_RINGING = "android.telecom.IN_CALL_SERVICE_RINGING";
     field public static final java.lang.String METADATA_IN_CALL_SERVICE_UI = "android.telecom.IN_CALL_SERVICE_UI";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -37277,6 +37443,26 @@
     method public void onSubscriptionsChanged();
   }
 
+  public final class TelephonyHistogram implements android.os.Parcelable {
+    ctor public TelephonyHistogram(int, int, int);
+    ctor public TelephonyHistogram(android.telephony.TelephonyHistogram);
+    ctor public TelephonyHistogram(android.os.Parcel);
+    method public void addTimeTaken(int);
+    method public int describeContents();
+    method public int getAverageTime();
+    method public int getBucketCount();
+    method public int[] getBucketCounters();
+    method public int[] getBucketEndPoints();
+    method public int getCategory();
+    method public int getId();
+    method public int getMaxTime();
+    method public int getMinTime();
+    method public int getSampleCount();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.telephony.TelephonyHistogram> CREATOR;
+    field public static final int TELEPHONY_CATEGORY_RIL = 1; // 0x1
+  }
+
   public class TelephonyManager {
     method public boolean canChangeDtmfToneLength();
     method public android.telephony.TelephonyManager createForSubscriptionId(int);
@@ -37307,6 +37493,7 @@
     method public java.lang.String getSimSerialNumber();
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
     method public java.lang.String getVoiceMailAlphaTag();
     method public java.lang.String getVoiceMailNumber();
     method public int getVoiceNetworkType();
@@ -41383,6 +41570,10 @@
     field public static final int KEYCODE_FOCUS = 80; // 0x50
     field public static final int KEYCODE_FORWARD = 125; // 0x7d
     field public static final int KEYCODE_FORWARD_DEL = 112; // 0x70
+    field public static final int KEYCODE_FP_NAV_DOWN = 281; // 0x119
+    field public static final int KEYCODE_FP_NAV_LEFT = 282; // 0x11a
+    field public static final int KEYCODE_FP_NAV_RIGHT = 283; // 0x11b
+    field public static final int KEYCODE_FP_NAV_UP = 280; // 0x118
     field public static final int KEYCODE_FUNCTION = 119; // 0x77
     field public static final int KEYCODE_G = 35; // 0x23
     field public static final int KEYCODE_GRAVE = 68; // 0x44
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index c597ed2..e8fcd3b 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -18,6 +18,9 @@
 #define LOG_TAG "BootAnimation"
 
 #include <stdint.h>
+#include <sys/inotify.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <math.h>
 #include <fcntl.h>
@@ -57,23 +60,29 @@
 #include "BootAnimation.h"
 #include "AudioPlayer.h"
 
-#define OEM_BOOTANIMATION_FILE "/oem/media/bootanimation.zip"
-#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
-#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
-#define EXIT_PROP_NAME "service.bootanim.exit"
-
 namespace android {
 
+static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
+static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
+static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
+static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
+static const char SYSTEM_TIME_DIR_NAME[] = "time";
+static const char SYSTEM_TIME_DIR_PATH[] = "/data/system/time";
+static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
+static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/system/time/last_time_change";
+static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
+static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/system/time/time_is_accurate";
+static const char EXIT_PROP_NAME[] = "service.bootanim.exit";
 static const int ANIM_ENTRY_NAME_MAX = 256;
 
 // ---------------------------------------------------------------------------
 
-BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true) {
+BootAnimation::BootAnimation() : Thread(false), mClockEnabled(true), mTimeIsAccurate(false),
+        mTimeCheckThread(NULL) {
     mSession = new SurfaceComposerClient();
 }
 
-BootAnimation::~BootAnimation() {
-}
+BootAnimation::~BootAnimation() {}
 
 void BootAnimation::onFirstRef() {
     status_t err = mSession->linkToComposerDeath(this);
@@ -638,11 +647,21 @@
 
 bool BootAnimation::movie()
 {
-
     Animation* animation = loadAnimation(mZipFileName);
     if (animation == NULL)
         return false;
 
+    bool anyPartHasClock = false;
+    for (size_t i=0; i < animation->parts.size(); i++) {
+        if(animation->parts[i].clockPosY >= 0) {
+            anyPartHasClock = true;
+            break;
+        }
+    }
+    if (!anyPartHasClock) {
+        mClockEnabled = false;
+    }
+
     // Blend required to draw time on top of animation frames.
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glShadeModel(GL_FLAT);
@@ -664,7 +683,18 @@
         mClockEnabled = clockTextureInitialized;
     }
 
+    if (mClockEnabled && !updateIsTimeAccurate()) {
+        mTimeCheckThread = new TimeCheckThread(this);
+        mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
+    }
+
     playAnimation(*animation);
+
+    if (mTimeCheckThread != NULL) {
+        mTimeCheckThread->requestExit();
+        mTimeCheckThread = NULL;
+    }
+
     releaseAnimation(animation);
 
     if (clockTextureInitialized) {
@@ -745,7 +775,7 @@
                 // which is equivalent to mHeight - (yc + animation.height)
                 glDrawTexiOES(xc, mHeight - (yc + animation.height),
                               0, animation.width, animation.height);
-                if (mClockEnabled && part.clockPosY >= 0) {
+                if (mClockEnabled && mTimeIsAccurate && part.clockPosY >= 0) {
                     drawTime(mClock, part.clockPosY);
                 }
 
@@ -824,6 +854,132 @@
     mLoadedFiles.remove(fn);
     return animation;
 }
+
+bool BootAnimation::updateIsTimeAccurate() {
+    static constexpr long long MAX_TIME_IN_PAST =   60000LL * 60LL * 24LL * 30LL;  // 30 days
+    static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL;  // 90 minutes
+
+    if (mTimeIsAccurate) {
+        return true;
+    }
+
+    struct stat statResult;
+    if(stat(ACCURATE_TIME_FLAG_FILE_PATH, &statResult) == 0) {
+        mTimeIsAccurate = true;
+        return true;
+    }
+
+    FILE* file = fopen(LAST_TIME_CHANGED_FILE_PATH, "r");
+    if (file != NULL) {
+      long long lastChangedTime = 0;
+      fscanf(file, "%lld", &lastChangedTime);
+      fclose(file);
+      if (lastChangedTime > 0) {
+        struct timespec now;
+        clock_gettime(CLOCK_REALTIME, &now);
+        // Match the Java timestamp format
+        long long rtcNow = (now.tv_sec * 1000LL) + (now.tv_nsec / 1000000LL);
+        if (lastChangedTime > rtcNow - MAX_TIME_IN_PAST
+            && lastChangedTime < rtcNow + MAX_TIME_IN_FUTURE) {
+            mTimeIsAccurate = true;
+        }
+      }
+    }
+
+    return mTimeIsAccurate;
+}
+
+BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) : Thread(false),
+    mInotifyFd(-1), mSystemWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
+
+BootAnimation::TimeCheckThread::~TimeCheckThread() {
+    // mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
+    close(mInotifyFd);
+}
+
+bool BootAnimation::TimeCheckThread::threadLoop() {
+    bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
+        && mBootAnimation->mClockEnabled;
+    if (!shouldLoop) {
+        close(mInotifyFd);
+        mInotifyFd = -1;
+    }
+    return shouldLoop;
+}
+
+bool BootAnimation::TimeCheckThread::doThreadLoop() {
+    static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
+
+    // Poll instead of doing a blocking read so the Thread can exit if requested.
+    struct pollfd pfd = { mInotifyFd, POLLIN, 0 };
+    ssize_t pollResult = poll(&pfd, 1, 1000);
+
+    if (pollResult == 0) {
+        return true;
+    } else if (pollResult < 0) {
+        ALOGE("Could not poll inotify events");
+        return false;
+    }
+
+    char buff[BUFF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));;
+    ssize_t length = read(mInotifyFd, buff, BUFF_LEN);
+    if (length == 0) {
+        return true;
+    } else if (length < 0) {
+        ALOGE("Could not read inotify events");
+        return false;
+    }
+
+    const struct inotify_event *event;
+    for (char* ptr = buff; ptr < buff + length; ptr += sizeof(struct inotify_event) + event->len) {
+        event = (const struct inotify_event *) ptr;
+        if (event->wd == mSystemWd && strcmp(SYSTEM_TIME_DIR_NAME, event->name) == 0) {
+            addTimeDirWatch();
+        } else if (event->wd == mTimeWd && (strcmp(LAST_TIME_CHANGED_FILE_NAME, event->name) == 0
+                || strcmp(ACCURATE_TIME_FLAG_FILE_NAME, event->name) == 0)) {
+            return !mBootAnimation->updateIsTimeAccurate();
+        }
+    }
+
+    return true;
+}
+
+void BootAnimation::TimeCheckThread::addTimeDirWatch() {
+        mTimeWd = inotify_add_watch(mInotifyFd, SYSTEM_TIME_DIR_PATH,
+                IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
+        if (mTimeWd > 0) {
+            // No need to watch for the time directory to be created if it already exists
+            inotify_rm_watch(mInotifyFd, mSystemWd);
+            mSystemWd = -1;
+        }
+}
+
+status_t BootAnimation::TimeCheckThread::readyToRun() {
+    mInotifyFd = inotify_init();
+    if (mInotifyFd < 0) {
+        ALOGE("Could not initialize inotify fd");
+        return NO_INIT;
+    }
+
+    mSystemWd = inotify_add_watch(mInotifyFd, SYSTEM_DATA_DIR_PATH, IN_CREATE | IN_ATTRIB);
+    if (mSystemWd < 0) {
+        close(mInotifyFd);
+        mInotifyFd = -1;
+        ALOGE("Could not add watch for %s", SYSTEM_DATA_DIR_PATH);
+        return NO_INIT;
+    }
+
+    addTimeDirWatch();
+
+    if (mBootAnimation->updateIsTimeAccurate()) {
+        close(mInotifyFd);
+        mInotifyFd = -1;
+        return ALREADY_EXISTS;
+    }
+
+    return NO_ERROR;
+}
+
 // ---------------------------------------------------------------------------
 
 }
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index d49e1ec..1c3d53a 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -51,6 +51,24 @@
     virtual void        onFirstRef();
     virtual void        binderDied(const wp<IBinder>& who);
 
+    bool                updateIsTimeAccurate();
+
+    class TimeCheckThread : public Thread {
+    public:
+        TimeCheckThread(BootAnimation* bootAnimation);
+        virtual ~TimeCheckThread();
+    private:
+        virtual status_t    readyToRun();
+        virtual bool        threadLoop();
+        bool                doThreadLoop();
+        void                addTimeDirWatch();
+
+        int mInotifyFd;
+        int mSystemWd;
+        int mTimeWd;
+        BootAnimation* mBootAnimation;
+    };
+
     struct Texture {
         GLint   w;
         GLint   h;
@@ -113,8 +131,10 @@
     sp<SurfaceControl> mFlingerSurfaceControl;
     sp<Surface> mFlingerSurface;
     bool        mClockEnabled;
+    bool        mTimeIsAccurate;
     String8     mZipFileName;
     SortedVector<String8> mLoadedFiles;
+    sp<TimeCheckThread> mTimeCheckThread;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/core/java/android/app/AlertDialog.java b/core/java/android/app/AlertDialog.java
index 7824072..9928512 100644
--- a/core/java/android/app/AlertDialog.java
+++ b/core/java/android/app/AlertDialog.java
@@ -201,7 +201,7 @@
                 createContextThemeWrapper);
 
         mWindow.alwaysReadCloseOnTouchAttr();
-        mAlert = new AlertController(getContext(), this, getWindow());
+        mAlert = AlertController.create(getContext(), this, getWindow());
     }
 
     static int resolveDialogTheme(Context context, int themeResId) {
diff --git a/core/java/android/app/WallpaperInfo.java b/core/java/android/app/WallpaperInfo.java
index 7db9fa8..84a16cf 100644
--- a/core/java/android/app/WallpaperInfo.java
+++ b/core/java/android/app/WallpaperInfo.java
@@ -31,6 +31,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.drawable.Drawable;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.service.wallpaper.WallpaperService;
@@ -72,6 +73,10 @@
      */
     final int mDescriptionResource;
 
+    final int mContextUriResource;
+    final int mContextDescriptionResource;
+    final boolean mShowMetadataInPreview;
+
     /**
      * Constructor.
      * 
@@ -89,7 +94,10 @@
         int thumbnailRes = -1;
         int authorRes = -1;
         int descriptionRes = -1;
-        
+        int contextUriRes = -1;
+        int contextDescriptionRes = -1;
+        boolean showMetadataInPreview = false;
+
         XmlResourceParser parser = null;
         try {
             parser = si.loadXmlMetaData(pm, WallpaperService.SERVICE_META_DATA);
@@ -127,6 +135,15 @@
             descriptionRes = sa.getResourceId(
                     com.android.internal.R.styleable.Wallpaper_description,
                     -1);
+            contextUriRes = sa.getResourceId(
+                    com.android.internal.R.styleable.Wallpaper_contextUri,
+                    -1);
+            contextDescriptionRes = sa.getResourceId(
+                    com.android.internal.R.styleable.Wallpaper_contextDescription,
+                    -1);
+            showMetadataInPreview = sa.getBoolean(
+                    com.android.internal.R.styleable.Wallpaper_showMetadataInPreview,
+                    false);
 
             sa.recycle();
         } catch (NameNotFoundException e) {
@@ -140,6 +157,9 @@
         mThumbnailResource = thumbnailRes;
         mAuthorResource = authorRes;
         mDescriptionResource = descriptionRes;
+        mContextUriResource = contextUriRes;
+        mContextDescriptionResource = contextDescriptionRes;
+        mShowMetadataInPreview = showMetadataInPreview;
     }
 
     WallpaperInfo(Parcel source) {
@@ -147,6 +167,9 @@
         mThumbnailResource = source.readInt();
         mAuthorResource = source.readInt();
         mDescriptionResource = source.readInt();
+        mContextUriResource = source.readInt();
+        mContextDescriptionResource = source.readInt();
+        mShowMetadataInPreview = source.readInt() != 0;
         mService = ResolveInfo.CREATOR.createFromParcel(source);
     }
     
@@ -248,7 +271,55 @@
         return pm.getText(packageName, mDescriptionResource,
                 mService.serviceInfo.applicationInfo);
     }
-    
+
+    /**
+     * Returns an URI that specifies a link for further context about this wallpaper.
+     *
+     * @param pm An instance of {@link PackageManager} to retrieve the URI.
+     * @return The URI.
+     */
+    public Uri loadContextUri(PackageManager pm) throws NotFoundException {
+        if (mContextUriResource <= 0) throw new NotFoundException();
+        String packageName = mService.resolvePackageName;
+        ApplicationInfo applicationInfo = null;
+        if (packageName == null) {
+            packageName = mService.serviceInfo.packageName;
+            applicationInfo = mService.serviceInfo.applicationInfo;
+        }
+        String contextUriString = pm.getText(
+                packageName, mContextUriResource, applicationInfo).toString();
+        if (contextUriString == null) {
+            return null;
+        }
+        return Uri.parse(contextUriString);
+    }
+
+    /**
+     * Retrieves a title of the URI that specifies a link for further context about this wallpaper.
+     *
+     * @param pm An instance of {@link PackageManager} to retrieve the title.
+     * @return The title.
+     */
+    public CharSequence loadContextDescription(PackageManager pm) throws NotFoundException {
+        if (mContextDescriptionResource <= 0) throw new NotFoundException();
+        String packageName = mService.resolvePackageName;
+        ApplicationInfo applicationInfo = null;
+        if (packageName == null) {
+            packageName = mService.serviceInfo.packageName;
+            applicationInfo = mService.serviceInfo.applicationInfo;
+        }
+        return pm.getText(packageName, mContextDescriptionResource, applicationInfo).toString();
+    }
+
+    /**
+     * Queries whether any metadata should be shown when previewing the wallpaper.
+     *
+     * @return Whether any metadata should be shown when previewing the wallpaper.
+     */
+    public boolean getShowMetadataInPreview() {
+        return mShowMetadataInPreview;
+    }
+
     /**
      * Return the class name of an activity that provides a settings UI for
      * the wallpaper.  You can launch this activity be starting it with
@@ -287,6 +358,9 @@
         dest.writeInt(mThumbnailResource);
         dest.writeInt(mAuthorResource);
         dest.writeInt(mDescriptionResource);
+        dest.writeInt(mContextUriResource);
+        dest.writeInt(mContextDescriptionResource);
+        dest.writeInt(mShowMetadataInPreview ? 1 : 0);
         mService.writeToParcel(dest, flags);
     }
 
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 24647f38..a0da258 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -79,6 +79,13 @@
         public static final int USER_INTERACTION = 7;
 
         /**
+         * An event type denoting that an action equivalent to a ShortcutInfo is taken by the user.
+         *
+         * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+         */
+        public static final int SHORTCUT_INVOCATION = 8;
+
+        /**
          * {@hide}
          */
         public String mPackage;
@@ -105,6 +112,13 @@
         public Configuration mConfiguration;
 
         /**
+         * ID of the shortcut.
+         * Only present for {@link #SHORTCUT_INVOCATION} event types.
+         * {@hide}
+         */
+        public String mShortcutId;
+
+        /**
          * The package name of the source of this event.
          */
         public String getPackageName() {
@@ -145,6 +159,16 @@
         public Configuration getConfiguration() {
             return mConfiguration;
         }
+
+        /**
+         * Returns the ID of a {@link android.content.pm.ShortcutInfo} for this event
+         * if the event is of type {@link #SHORTCUT_INVOCATION}, otherwise it returns null.
+         *
+         * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+         */
+        public String getShortcutId() {
+            return mShortcutId;
+        }
     }
 
     // Only used when creating the resulting events. Not used for reading/unparceling.
@@ -276,8 +300,13 @@
         p.writeInt(event.mEventType);
         p.writeLong(event.mTimeStamp);
 
-        if (event.mEventType == Event.CONFIGURATION_CHANGE) {
-            event.mConfiguration.writeToParcel(p, flags);
+        switch (event.mEventType) {
+            case Event.CONFIGURATION_CHANGE:
+                event.mConfiguration.writeToParcel(p, flags);
+                break;
+            case Event.SHORTCUT_INVOCATION:
+                p.writeString(event.mShortcutId);
+                break;
         }
     }
 
@@ -301,11 +330,18 @@
         eventOut.mEventType = p.readInt();
         eventOut.mTimeStamp = p.readLong();
 
-        // Extract the configuration for configuration change events.
-        if (eventOut.mEventType == Event.CONFIGURATION_CHANGE) {
-            eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p);
-        } else {
-            eventOut.mConfiguration = null;
+        // Fill out the event-dependant fields.
+        eventOut.mConfiguration = null;
+        eventOut.mShortcutId = null;
+
+        switch (eventOut.mEventType) {
+            case Event.CONFIGURATION_CHANGE:
+                // Extract the configuration for configuration change events.
+                eventOut.mConfiguration = Configuration.CREATOR.createFromParcel(p);
+                break;
+            case Event.SHORTCUT_INVOCATION:
+                eventOut.mShortcutId = p.readString();
+                break;
         }
     }
 
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b6f1567..a6f91fe 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -56,6 +56,17 @@
     public abstract void reportConfigurationChange(Configuration config, int userId);
 
     /**
+     * Reports that an action equivalent to a ShortcutInfo is taken by the user.
+     *
+     * @param packageName The package name of the shortcut publisher
+     * @param shortcutId The ID of the shortcut in question
+     * @param userId The user in which the content provider was accessed.
+     *
+     * @see android.content.pm.ShortcutManager#reportShortcutUsed(String)
+     */
+    public abstract void reportShortcutUsage(String packageName, String shortcutId, int userId);
+
+    /**
      * Reports that a content provider has been accessed by a foreground app.
      * @param name The authority of the content provider
      * @param pkgName The package name of the content provider
diff --git a/core/java/android/appwidget/AppWidgetHost.java b/core/java/android/appwidget/AppWidgetHost.java
index 2d9f4a7..cd14469 100644
--- a/core/java/android/appwidget/AppWidgetHost.java
+++ b/core/java/android/appwidget/AppWidgetHost.java
@@ -34,7 +34,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.util.DisplayMetrics;
 import android.util.SparseArray;
 import android.util.TypedValue;
@@ -187,19 +186,28 @@
                 idsToUpdate[i] = mViews.keyAt(i);
             }
         }
-        List<RemoteViews> updatedViews;
-        int[] updatedIds = new int[idsToUpdate.length];
+        List<PendingHostUpdate> updates;
         try {
-            updatedViews = sService.startListening(
-                    mCallbacks, mContextOpPackageName, mHostId, idsToUpdate, updatedIds).getList();
+            updates = sService.startListening(
+                    mCallbacks, mContextOpPackageName, mHostId, idsToUpdate).getList();
         }
         catch (RemoteException e) {
             throw new RuntimeException("system server dead?", e);
         }
 
-        int N = updatedViews.size();
+        int N = updates.size();
         for (int i = 0; i < N; i++) {
-            updateAppWidgetView(updatedIds[i], updatedViews.get(i));
+            PendingHostUpdate update = updates.get(i);
+            switch (update.type) {
+                case PendingHostUpdate.TYPE_VIEWS_UPDATE:
+                    updateAppWidgetView(update.appWidgetId, update.views);
+                    break;
+                case PendingHostUpdate.TYPE_PROVIDER_CHANGED:
+                    onProviderChanged(update.appWidgetId, update.widgetInfo);
+                    break;
+                case PendingHostUpdate.TYPE_VIEW_DATA_CHANGED:
+                    viewDataChanged(update.appWidgetId, update.viewId);
+            }
         }
     }
 
diff --git a/core/java/android/appwidget/PendingHostUpdate.java b/core/java/android/appwidget/PendingHostUpdate.java
new file mode 100644
index 0000000..5780319
--- /dev/null
+++ b/core/java/android/appwidget/PendingHostUpdate.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.appwidget;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.widget.RemoteViews;
+
+/**
+ * @hide
+ */
+public class PendingHostUpdate implements Parcelable {
+
+    static final int TYPE_VIEWS_UPDATE = 0;
+    static final int TYPE_PROVIDER_CHANGED = 1;
+    static final int TYPE_VIEW_DATA_CHANGED = 2;
+
+    final int appWidgetId;
+    final int type;
+    RemoteViews views;
+    AppWidgetProviderInfo widgetInfo;
+    int viewId;
+
+    public static PendingHostUpdate updateAppWidget(int appWidgetId, RemoteViews views) {
+        PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEWS_UPDATE);
+        update.views = views;
+        return update;
+    }
+
+    public static PendingHostUpdate providerChanged(int appWidgetId, AppWidgetProviderInfo info) {
+        PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_PROVIDER_CHANGED);
+        update.widgetInfo = info;
+        return update;
+    }
+
+    public static PendingHostUpdate viewDataChanged(int appWidgetId, int viewId) {
+        PendingHostUpdate update = new PendingHostUpdate(appWidgetId, TYPE_VIEW_DATA_CHANGED);
+        update.viewId = viewId;
+        return update;
+    }
+
+    private PendingHostUpdate(int appWidgetId, int type) {
+        this.appWidgetId = appWidgetId;
+        this.type = type;
+    }
+
+    private PendingHostUpdate(Parcel in) {
+        appWidgetId = in.readInt();
+        type = in.readInt();
+
+        switch (type) {
+            case TYPE_VIEWS_UPDATE:
+                if (0 != in.readInt()) {
+                    views = new RemoteViews(in);
+                }
+                break;
+            case TYPE_PROVIDER_CHANGED:
+                if (0 != in.readInt()) {
+                    widgetInfo = new AppWidgetProviderInfo(in);
+                }
+                break;
+            case TYPE_VIEW_DATA_CHANGED:
+                viewId = in.readInt();
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(appWidgetId);
+        dest.writeInt(type);
+        switch (type) {
+            case TYPE_VIEWS_UPDATE:
+                writeNullParcelable(views, dest, flags);
+                break;
+            case TYPE_PROVIDER_CHANGED:
+                writeNullParcelable(widgetInfo, dest, flags);
+                break;
+            case TYPE_VIEW_DATA_CHANGED:
+                dest.writeInt(viewId);
+                break;
+        }
+    }
+
+    private void writeNullParcelable(Parcelable p, Parcel dest, int flags) {
+        if (p != null) {
+            dest.writeInt(1);
+            p.writeToParcel(dest, flags);
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
+    /**
+     * Parcelable.Creator that instantiates PendingHostUpdate objects
+     */
+    public static final Parcelable.Creator<PendingHostUpdate> CREATOR
+            = new Parcelable.Creator<PendingHostUpdate>() {
+        public PendingHostUpdate createFromParcel(Parcel parcel) {
+            return new PendingHostUpdate(parcel);
+        }
+
+        public PendingHostUpdate[] newArray(int size) {
+            return new PendingHostUpdate[size];
+        }
+    };
+}
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 09a15de..f46a3b3 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -220,6 +220,46 @@
      * {@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} of
      * {@link #ACTION_AUDIO_STATE_CHANGED} intent.
      */
+
+    /**
+     * Intent used to broadcast the headset's indicator status
+     *
+     * <p>This intent will have 3 extras:
+     * <ul>
+     *   <li> {@link #EXTRA_IND_ID} - The Assigned number of headset Indicator which is supported by
+                                        the headset ( as indicated by AT+BIND
+                                        command in the SLC sequence).or whose value
+                                        is changed (indicated by AT+BIEV command)</li>
+     *   <li> {@link #EXTRA_IND_VALUE}- The updated value of headset indicator. </li>
+     *   <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+     * </ul>
+     * <p>{@link #EXTRA_IND_ID} is defined by Bluetooth SIG and each of the indicators are
+     * given an assigned number. Below shows the assigned number of Indicator added so far
+     * - Enhanced Safety - 1
+     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
+     * receive.
+     * @hide
+     */
+    public static final String ACTION_HF_INDICATORS_VALUE_CHANGED =
+            "android.bluetooth.headset.action.HF_INDICATORS_VALUE_CHANGED";
+
+    /**
+     * A String extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+     * intents that contains the UUID of the headset  indicator (as defined by Bluetooth SIG)
+     * that is being sent.
+     * @hide
+     */
+    public static final String EXTRA_HF_INDICATORS_IND_ID =
+            "android.bluetooth.headset.extra.HF_INDICATORS_IND_ID";
+
+    /**
+     * A int  extra field in {@link #ACTION_HF_INDICATORS_VALUE_CHANGED}
+     * intents that contains the value of the Headset indicator that is being sent.
+     * @hide
+     */
+    public static final String EXTRA_HF_INDICATORS_IND_VALUE =
+            "android.bluetooth.headset.extra.HF_INDICATORS_IND_VALUE";
+
     public static final int STATE_AUDIO_CONNECTED = 12;
 
     private static final int MESSAGE_HEADSET_SERVICE_CONNECTED = 100;
@@ -969,6 +1009,29 @@
         return false;
     }
 
+    /**
+     * Send Headset the BIND response from AG to report change in the status of the
+     * HF indicators to the headset
+     *
+     * @param ind_id Assigned Number of the indicator (defined by SIG)
+     * @param ind_status
+     * possible values- false-Indicator is disabled, no value changes shall be sent for this indicator
+     *                  true-Indicator is enabled, value changes may be sent for this indicator
+     * @hide
+     */
+    public void bindResponse(int ind_id, boolean ind_status) {
+        if (mService != null && isEnabled()) {
+            try {
+                mService.bindResponse(ind_id, ind_status);
+            } catch (RemoteException e) {
+                Log.e(TAG, e.toString());
+            }
+        } else {
+            Log.w(TAG, "Proxy not attached to service");
+            if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
+        }
+    }
+
     private final IBluetoothProfileServiceConnection mConnection
             = new IBluetoothProfileServiceConnection.Stub()  {
         @Override
diff --git a/core/java/android/bluetooth/IBluetoothHeadset.aidl b/core/java/android/bluetooth/IBluetoothHeadset.aidl
index 0bb4088..6ad442b 100755
--- a/core/java/android/bluetooth/IBluetoothHeadset.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadset.aidl
@@ -59,4 +59,5 @@
                       String number, int type);
     boolean enableWBS();
     boolean disableWBS();
+    void bindResponse(int ind_id, boolean ind_status);
 }
diff --git a/core/java/android/bluetooth/IBluetoothManager.aidl b/core/java/android/bluetooth/IBluetoothManager.aidl
index 0b81ee8..2b853a3 100644
--- a/core/java/android/bluetooth/IBluetoothManager.aidl
+++ b/core/java/android/bluetooth/IBluetoothManager.aidl
@@ -37,6 +37,7 @@
     boolean enable();
     boolean enableNoAutoConnect();
     boolean disable(boolean persist);
+    int getState();
     IBluetoothGatt getBluetoothGatt();
 
     boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 108350a..8b3eac5 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3619,8 +3619,6 @@
      *
      * @see #getSystemService
      * @see android.content.pm.ShortcutManager
-     *
-     * @hide
      */
     public static final String SHORTCUT_SERVICE = "shortcut";
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9118f01..df2c6fc 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3174,6 +3174,14 @@
     public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
 
     /**
+     * Boolean intent extra to be used with {@link ACTION_MASTER_CLEAR} in order to force a factory
+     * reset even if {@link android.os.UserManager.DISALLOW_FACTORY_RESET} is set.
+     * @hide
+     */
+    public static final String EXTRA_FORCE_MASTER_CLEAR =
+            "android.intent.extra.FORCE_MASTER_CLEAR";
+
+    /**
      * Broadcast action: report that a settings element is being restored from backup.  The intent
      * contains three extras: EXTRA_SETTING_NAME is a string naming the restored setting,
      * EXTRA_SETTING_NEW_VALUE is the value being restored, and EXTRA_SETTING_PREVIOUS_VALUE
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 2ba24f6..1c373f9 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -28,6 +28,8 @@
 
     ParceledListSlice getDynamicShortcuts(String packageName, int userId);
 
+    ParceledListSlice getManifestShortcuts(String packageName, int userId);
+
     boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList,
             int userId);
 
@@ -39,6 +41,11 @@
 
     boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId);
 
+    void disableShortcuts(String packageName, in List shortcutIds, String disabledMessage,
+            int disabledMessageResId, int userId);
+
+    void enableShortcuts(String packageName, in List shortcutIds, int userId);
+
     int getMaxDynamicShortcutCount(String packageName, int userId);
 
     int getRemainingCallCount(String packageName, int userId);
@@ -47,6 +54,8 @@
 
     int getIconMaxDimensions(String packageName, int userId);
 
+    void reportShortcutUsed(String packageName, String shortcutId, int userId);
+
     void resetThrottling(); // system only API for developer opsions
 
     void onApplicationActive(String packageName, int userId); // system only API for sysUI
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 8ca27c5..6cb50fc 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -24,7 +24,13 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
 import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -34,8 +40,10 @@
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.DisplayMetrics;
 import android.util.Log;
 
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -166,8 +174,6 @@
          * @param shortcuts all shortcuts from the package (dynamic and/or pinned).  Only "key"
          *    information will be provided, as defined in {@link ShortcutInfo#hasKeyFieldsOnly()}.
          * @param user The UserHandle of the profile that generated the change.
-         *
-         * @hide
          */
         public void onShortcutsChanged(@NonNull String packageName,
                 @NonNull List<ShortcutInfo> shortcuts, @NonNull UserHandle user) {
@@ -176,8 +182,6 @@
 
     /**
      * Represents a query passed to {@link #getShortcuts(ShortcutQuery, UserHandle)}.
-     *
-     * @hide
      */
     public static class ShortcutQuery {
         /**
@@ -191,6 +195,11 @@
         public static final int FLAG_GET_PINNED = 1 << 1;
 
         /**
+         * Include manifest shortcuts in the result.
+         */
+        public static final int FLAG_GET_MANIFEST = 1 << 3;
+
+        /**
          * Requests "key" fields only.  See {@link ShortcutInfo#hasKeyFieldsOnly()} for which
          * fields are available.
          */
@@ -201,6 +210,7 @@
                 value = {
                         FLAG_GET_DYNAMIC,
                         FLAG_GET_PINNED,
+                        FLAG_GET_MANIFEST,
                         FLAG_GET_KEY_FIELDS_ONLY,
                 })
         @Retention(RetentionPolicy.SOURCE)
@@ -227,37 +237,44 @@
          * If non-zero, returns only shortcuts that have been added or updated since the timestamp,
          * which is a milliseconds since the Epoch.
          */
-        public void setChangedSince(long changedSince) {
+        public ShortcutQuery setChangedSince(long changedSince) {
             mChangedSince = changedSince;
+            return this;
         }
 
         /**
          * If non-null, returns only shortcuts from the package.
          */
-        public void setPackage(@Nullable String packageName) {
+        public ShortcutQuery setPackage(@Nullable String packageName) {
             mPackage = packageName;
+            return this;
         }
 
         /**
          * If non-null, return only the specified shortcuts by ID.  When setting this field,
          * a packange name must also be set with {@link #setPackage}.
          */
-        public void setShortcutIds(@Nullable List<String> shortcutIds) {
+        public ShortcutQuery setShortcutIds(@Nullable List<String> shortcutIds) {
             mShortcutIds = shortcutIds;
+            return this;
         }
 
         /**
-         * If non-null, returns only shortcuts associated with the activity.
+         * If non-null, returns only shortcuts associated with the activity; i.e.
+         * {@link ShortcutInfo}s whose {@link ShortcutInfo#getActivity()} are equal
+         * to {@code activity}.
          */
-        public void setActivity(@Nullable ComponentName activity) {
+        public ShortcutQuery setActivity(@Nullable ComponentName activity) {
             mActivity = activity;
+            return this;
         }
 
         /**
          * Set query options.
          */
-        public void setQueryFlags(@QueryFlags int queryFlags) {
+        public ShortcutQuery setQueryFlags(@QueryFlags int queryFlags) {
             mQueryFlags = queryFlags;
+            return this;
         }
     }
 
@@ -426,8 +443,6 @@
      * the user is trying a new launcher application.  The user may decide to change the default
      * launcher to the calling application again, so even if a launcher application loses
      * this permission, it does <b>not</b> have to purge pinned shortcut information.
-     *
-     * @hide
      */
     public boolean hasShortcutHostPermission() {
         try {
@@ -447,8 +462,6 @@
      * @param user The UserHandle of the profile.
      *
      * @return the IDs of {@link ShortcutInfo}s that match the query.
-     *
-     * @hide
      */
     @Nullable
     public List<ShortcutInfo> getShortcuts(@NonNull ShortcutQuery query,
@@ -488,8 +501,6 @@
      * @param packageName The target package name.
      * @param shortcutIds The IDs of the shortcut to be pinned.
      * @param user The UserHandle of the profile.
-     *
-     * @hide
      */
     public void pinShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds,
             @NonNull UserHandle user) {
@@ -529,12 +540,10 @@
      * #hasShortcutHostPermission()}.
      *
      * @param shortcut The target shortcut.
-     *
-     * @hide
      */
     public ParcelFileDescriptor getShortcutIconFd(
             @NonNull ShortcutInfo shortcut) {
-        return getShortcutIconFd(shortcut.getPackageName(), shortcut.getId(),
+        return getShortcutIconFd(shortcut.getPackage(), shortcut.getId(),
                 shortcut.getUserId());
     }
 
@@ -548,8 +557,6 @@
      * @param packageName The target package name.
      * @param shortcutId The ID of the shortcut to lad rom.
      * @param user The UserHandle of the profile.
-     *
-     * @hide
      */
     public ParcelFileDescriptor getShortcutIconFd(
             @NonNull String packageName, @NonNull String shortcutId, @NonNull UserHandle user) {
@@ -567,6 +574,63 @@
     }
 
     /**
+     * Returns the icon for this shortcut, without any badging for the profile.
+     *
+     * @param density The preferred density of the icon, zero for default density. Use
+     * density DPI values from {@link DisplayMetrics}.
+     * @see #getShortcutBadgedIconDrawable(ShortcutInfo, int)
+     * @see DisplayMetrics
+     * @return The drawable associated with the shortcut.
+     */
+    public Drawable getShortcutIconDrawable(@NonNull ShortcutInfo shortcut, int density) {
+        if (shortcut.hasIconFile()) {
+            final ParcelFileDescriptor pfd = getShortcutIconFd(shortcut);
+            if (pfd == null) {
+                return null;
+            }
+            try {
+                final Bitmap bmp = BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
+                return (bmp == null) ? null : new BitmapDrawable(mContext.getResources(), bmp);
+            } finally {
+                try {
+                    pfd.close();
+                } catch (IOException ignore) {
+                }
+            }
+        } else if (shortcut.hasIconResource()) {
+            try {
+                final int resId = shortcut.getIconResourceId();
+                if (resId == 0) {
+                    return null; // Shouldn't happen but just in case.
+                }
+                final ApplicationInfo ai = getApplicationInfo(shortcut.getPackage(),
+                        /* flags =*/ 0, shortcut.getUserHandle());
+                final Resources res = mContext.getPackageManager().getResourcesForApplication(ai);
+                return res.getDrawableForDensity(resId, density);
+            } catch (NameNotFoundException | Resources.NotFoundException e) {
+                return null;
+            }
+        } else {
+            return null; // Has no icon.
+        }
+    }
+
+    /**
+     * Returns the shortcut icon with badging appropriate for the profile.
+     *
+     * @param density Optional density for the icon, or 0 to use the default density. Use
+     * {@link DisplayMetrics} for DPI values.
+     * @see DisplayMetrics
+     * @return A badged icon for the shortcut.
+     */
+    public Drawable getShortcutBadgedIconDrawable(ShortcutInfo shortcut, int density) {
+        final Drawable originalIcon = getShortcutIconDrawable(shortcut, density);
+
+        return (originalIcon == null) ? null : mContext.getPackageManager().getUserBadgedIcon(
+                originalIcon, shortcut.getUserHandle());
+    }
+
+    /**
      * Launches a shortcut.
      *
      * <p>Callers must be allowed to access the shortcut information, as defined in {@link
@@ -579,8 +643,6 @@
      * @param user The UserHandle of the profile.
      * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
      *   has been uninstalled). {@code true} when the shortcut is still valid.
-     *
-     * @hide
      */
     public boolean startShortcut(@NonNull String packageName, @NonNull String shortcutId,
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions,
@@ -600,12 +662,10 @@
      * @param startActivityOptions Options to pass to startActivity.
      * @return {@code false} when the shortcut is no longer valid (e.g. the creator application
      *   has been uninstalled). {@code true} when the shortcut is still valid.
-     *
-     * @hide
      */
     public boolean startShortcut(@NonNull ShortcutInfo shortcut,
             @Nullable Rect sourceBounds, @Nullable Bundle startActivityOptions) {
-        return startShortcut(shortcut.getPackageName(), shortcut.getId(),
+        return startShortcut(shortcut.getPackage(), shortcut.getId(),
                 sourceBounds, startActivityOptions,
                 shortcut.getUserId());
     }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index adf9fe6..fffdf717 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -270,6 +270,7 @@
         final int nameRes;
         final int labelRes;
         final int iconRes;
+        final int roundIconRes;
         final int logoRes;
         final int bannerRes;
 
@@ -277,7 +278,8 @@
         TypedArray sa;
 
         ParsePackageItemArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes) {
+                int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
+                int _bannerRes) {
             owner = _owner;
             outError = _outError;
             nameRes = _nameRes;
@@ -285,6 +287,7 @@
             iconRes = _iconRes;
             logoRes = _logoRes;
             bannerRes = _bannerRes;
+            roundIconRes = _roundIconRes;
         }
     }
 
@@ -296,10 +299,12 @@
         int flags;
 
         ParseComponentArgs(Package _owner, String[] _outError,
-                int _nameRes, int _labelRes, int _iconRes, int _logoRes, int _bannerRes,
+                int _nameRes, int _labelRes, int _iconRes, int _roundIconRes, int _logoRes,
+                int _bannerRes,
                 String[] _sepProcesses, int _processRes,
                 int _descriptionRes, int _enabledRes) {
-            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _logoRes, _bannerRes);
+            super(_owner, _outError, _nameRes, _labelRes, _iconRes, _roundIconRes, _logoRes,
+                    _bannerRes);
             sepProcesses = _sepProcesses;
             processRes = _processRes;
             descriptionRes = _descriptionRes;
@@ -2508,10 +2513,11 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup);
 
         if (!parsePackageItemInfo(owner, perm.info, outError,
-                "<permission-group>", sa,
+                "<permission-group>", sa, true /*nameRequired*/,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_icon,
+                com.android.internal.R.styleable.AndroidManifestPermissionGroup_roundIcon,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_logo,
                 com.android.internal.R.styleable.AndroidManifestPermissionGroup_banner)) {
             sa.recycle();
@@ -2552,10 +2558,11 @@
                 com.android.internal.R.styleable.AndroidManifestPermission);
 
         if (!parsePackageItemInfo(owner, perm.info, outError,
-                "<permission>", sa,
+                "<permission>", sa, true /*nameRequired*/,
                 com.android.internal.R.styleable.AndroidManifestPermission_name,
                 com.android.internal.R.styleable.AndroidManifestPermission_label,
                 com.android.internal.R.styleable.AndroidManifestPermission_icon,
+                com.android.internal.R.styleable.AndroidManifestPermission_roundIcon,
                 com.android.internal.R.styleable.AndroidManifestPermission_logo,
                 com.android.internal.R.styleable.AndroidManifestPermission_banner)) {
             sa.recycle();
@@ -2621,10 +2628,11 @@
                 com.android.internal.R.styleable.AndroidManifestPermissionTree);
 
         if (!parsePackageItemInfo(owner, perm.info, outError,
-                "<permission-tree>", sa,
+                "<permission-tree>", sa, true /*nameRequired*/,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_name,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_label,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_icon,
+                com.android.internal.R.styleable.AndroidManifestPermissionTree_roundIcon,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_logo,
                 com.android.internal.R.styleable.AndroidManifestPermissionTree_banner)) {
             sa.recycle();
@@ -2671,6 +2679,7 @@
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_name,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_label,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_icon,
+                    com.android.internal.R.styleable.AndroidManifestInstrumentation_roundIcon,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_logo,
                     com.android.internal.R.styleable.AndroidManifestInstrumentation_banner);
             mParseInstrumentationArgs.tag = "<instrumentation>";
@@ -2736,10 +2745,21 @@
         TypedArray sa = res.obtainAttributes(parser,
                 com.android.internal.R.styleable.AndroidManifestApplication);
 
-        String name = sa.getNonConfigurationString(
-                com.android.internal.R.styleable.AndroidManifestApplication_name, 0);
-        if (name != null) {
-            ai.className = buildClassName(pkgName, name, outError);
+        if (!parsePackageItemInfo(owner, ai, outError,
+                "<application>", sa, false /*nameRequired*/,
+                com.android.internal.R.styleable.AndroidManifestApplication_name,
+                com.android.internal.R.styleable.AndroidManifestApplication_label,
+                com.android.internal.R.styleable.AndroidManifestApplication_icon,
+                com.android.internal.R.styleable.AndroidManifestApplication_roundIcon,
+                com.android.internal.R.styleable.AndroidManifestApplication_logo,
+                com.android.internal.R.styleable.AndroidManifestApplication_banner)) {
+            sa.recycle();
+            mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+            return false;
+        }
+
+        if (ai.name != null) {
+            ai.className = buildClassName(pkgName, ai.name, outError);
             if (ai.className == null) {
                 sa.recycle();
                 mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
@@ -2810,18 +2830,6 @@
             }
         }
 
-        TypedValue v = sa.peekValue(
-                com.android.internal.R.styleable.AndroidManifestApplication_label);
-        if (v != null && (ai.labelRes=v.resourceId) == 0) {
-            ai.nonLocalizedLabel = v.coerceToString();
-        }
-
-        ai.icon = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestApplication_icon, 0);
-        ai.logo = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestApplication_logo, 0);
-        ai.banner = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestApplication_banner, 0);
         ai.theme = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestApplication_theme, 0);
         ai.descriptionRes = sa.getResourceId(
@@ -3335,25 +3343,33 @@
         return true;
     }
 
-    private boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
-            String[] outError, String tag, TypedArray sa,
-            int nameRes, int labelRes, int iconRes, int logoRes, int bannerRes) {
+    private static boolean parsePackageItemInfo(Package owner, PackageItemInfo outInfo,
+            String[] outError, String tag, TypedArray sa, boolean nameRequired,
+            int nameRes, int labelRes, int iconRes, int roundIconRes, int logoRes, int bannerRes) {
         String name = sa.getNonConfigurationString(nameRes, 0);
         if (name == null) {
-            outError[0] = tag + " does not specify android:name";
-            return false;
+            if (nameRequired) {
+                outError[0] = tag + " does not specify android:name";
+                return false;
+            }
+        } else {
+            outInfo.name
+                = buildClassName(owner.applicationInfo.packageName, name, outError);
+            if (outInfo.name == null) {
+                return false;
+            }
         }
 
-        outInfo.name
-            = buildClassName(owner.applicationInfo.packageName, name, outError);
-        if (outInfo.name == null) {
-            return false;
-        }
-
-        int iconVal = sa.getResourceId(iconRes, 0);
-        if (iconVal != 0) {
-            outInfo.icon = iconVal;
+        int roundIconVal = sa.getResourceId(roundIconRes, 0);
+        if (roundIconVal != 0) {
+            outInfo.icon = roundIconVal;
             outInfo.nonLocalizedLabel = null;
+        } else {
+            int iconVal = sa.getResourceId(iconRes, 0);
+            if (iconVal != 0) {
+                outInfo.icon = iconVal;
+                outInfo.nonLocalizedLabel = null;
+            }
         }
 
         int logoVal = sa.getResourceId(logoRes, 0);
@@ -3387,6 +3403,7 @@
                     R.styleable.AndroidManifestActivity_name,
                     R.styleable.AndroidManifestActivity_label,
                     R.styleable.AndroidManifestActivity_icon,
+                    R.styleable.AndroidManifestActivity_roundIcon,
                     R.styleable.AndroidManifestActivity_logo,
                     R.styleable.AndroidManifestActivity_banner,
                     mSeparateProcesses,
@@ -3761,6 +3778,7 @@
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_name,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_label,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_icon,
+                    com.android.internal.R.styleable.AndroidManifestActivityAlias_roundIcon,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_logo,
                     com.android.internal.R.styleable.AndroidManifestActivityAlias_banner,
                     mSeparateProcesses,
@@ -3915,6 +3933,7 @@
                     com.android.internal.R.styleable.AndroidManifestProvider_name,
                     com.android.internal.R.styleable.AndroidManifestProvider_label,
                     com.android.internal.R.styleable.AndroidManifestProvider_icon,
+                    com.android.internal.R.styleable.AndroidManifestProvider_roundIcon,
                     com.android.internal.R.styleable.AndroidManifestProvider_logo,
                     com.android.internal.R.styleable.AndroidManifestProvider_banner,
                     mSeparateProcesses,
@@ -4234,6 +4253,7 @@
                     com.android.internal.R.styleable.AndroidManifestService_name,
                     com.android.internal.R.styleable.AndroidManifestService_label,
                     com.android.internal.R.styleable.AndroidManifestService_icon,
+                    com.android.internal.R.styleable.AndroidManifestService_roundIcon,
                     com.android.internal.R.styleable.AndroidManifestService_logo,
                     com.android.internal.R.styleable.AndroidManifestService_banner,
                     mSeparateProcesses,
@@ -4550,8 +4570,14 @@
             outInfo.nonLocalizedLabel = v.coerceToString();
         }
 
-        outInfo.icon = sa.getResourceId(
-                com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
+        int roundIcon = sa.getResourceId(
+                com.android.internal.R.styleable.AndroidManifestIntentFilter_roundIcon, 0);
+        if (roundIcon != 0) {
+            outInfo.icon = roundIcon;
+        } else {
+            outInfo.icon = sa.getResourceId(
+                    com.android.internal.R.styleable.AndroidManifestIntentFilter_icon, 0);
+        }
 
         outInfo.logo = sa.getResourceId(
                 com.android.internal.R.styleable.AndroidManifestIntentFilter_logo, 0);
@@ -5180,45 +5206,13 @@
         public Component(final ParsePackageItemArgs args, final PackageItemInfo outInfo) {
             owner = args.owner;
             intents = new ArrayList<II>(0);
-            String name = args.sa.getNonConfigurationString(args.nameRes, 0);
-            if (name == null) {
+            if (parsePackageItemInfo(args.owner, outInfo, args.outError, args.tag, args.sa,
+                    true /*nameRequired*/, args.nameRes, args.labelRes, args.iconRes,
+                    args.roundIconRes, args.logoRes, args.bannerRes)) {
+                className = outInfo.name;
+            } else {
                 className = null;
-                args.outError[0] = args.tag + " does not specify android:name";
-                return;
             }
-
-            outInfo.name
-                = buildClassName(owner.applicationInfo.packageName, name, args.outError);
-            if (outInfo.name == null) {
-                className = null;
-                args.outError[0] = args.tag + " does not have valid android:name";
-                return;
-            }
-
-            className = outInfo.name;
-
-            int iconVal = args.sa.getResourceId(args.iconRes, 0);
-            if (iconVal != 0) {
-                outInfo.icon = iconVal;
-                outInfo.nonLocalizedLabel = null;
-            }
-
-            int logoVal = args.sa.getResourceId(args.logoRes, 0);
-            if (logoVal != 0) {
-                outInfo.logo = logoVal;
-            }
-
-            int bannerVal = args.sa.getResourceId(args.bannerRes, 0);
-            if (bannerVal != 0) {
-                outInfo.banner = bannerVal;
-            }
-
-            TypedValue v = args.sa.peekValue(args.labelRes);
-            if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
-                outInfo.nonLocalizedLabel = v.coerceToString();
-            }
-
-            outInfo.packageName = owner.packageName;
         }
 
         public Component(final ParseComponentArgs args, final ComponentInfo outInfo) {
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 4340d04..28e7887 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -22,6 +22,8 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -50,8 +52,6 @@
  * </ul>
  *
  * @see {@link ShortcutManager}.
- *
- * @hide
  */
 public final class ShortcutInfo implements Parcelable {
     /* @hide */
@@ -69,6 +69,18 @@
     /* @hide */
     public static final int FLAG_KEY_FIELDS_ONLY = 1 << 4;
 
+    /* @hide */
+    public static final int FLAG_MANIFEST = 1 << 5;
+
+    /* @hide */
+    public static final int FLAG_DISABLED = 1 << 6;
+
+    /* @hide */
+    public static final int FLAG_STRINGS_RESOLVED = 1 << 7;
+
+    /* @hide */
+    public static final int FLAG_IMMUTABLE = 1 << 8;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
@@ -77,6 +89,10 @@
             FLAG_HAS_ICON_RES,
             FLAG_HAS_ICON_FILE,
             FLAG_KEY_FIELDS_ONLY,
+            FLAG_MANIFEST,
+            FLAG_DISABLED,
+            FLAG_STRINGS_RESOLVED,
+            FLAG_IMMUTABLE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -121,33 +137,42 @@
     private final String mPackageName;
 
     @Nullable
-    private ComponentName mActivityComponent;
+    private ComponentName mActivity;
 
     @Nullable
     private Icon mIcon;
 
-    @NonNull
-    private String mTitle;
+    private int mTitleResId;
 
     @Nullable
-    private String mText;
+    private CharSequence mTitle;
 
-    @NonNull
+    private int mTextResId;
+
+    @Nullable
+    private CharSequence mText;
+
+    private int mDisabledMessageResId;
+
+    @Nullable
+    private CharSequence mDisabledMessage;
+
+    @Nullable
     private ArraySet<String> mCategories;
 
     /**
      * Intent *with extras removed*.
      */
-    @NonNull
+    @Nullable
     private Intent mIntent;
 
     /**
      * Extras for the intent.
      */
-    @NonNull
+    @Nullable
     private PersistableBundle mIntentPersistableExtras;
 
-    private int mWeight;
+    private int mRank;
 
     @Nullable
     private PersistableBundle mExtras;
@@ -175,10 +200,14 @@
         // Note we can't do other null checks here because SM.updateShortcuts() takes partial
         // information.
         mPackageName = b.mContext.getPackageName();
-        mActivityComponent = b.mActivityComponent;
+        mActivity = b.mActivity;
         mIcon = b.mIcon;
         mTitle = b.mTitle;
+        mTitleResId = b.mTitleResId;
         mText = b.mText;
+        mTextResId = b.mTextResId;
+        mDisabledMessage = b.mDisabledMessage;
+        mDisabledMessageResId = b.mDisabledMessageResId;
         mCategories = clone(b.mCategories);
         mIntent = b.mIntent;
         if (mIntent != null) {
@@ -188,7 +217,7 @@
                 mIntentPersistableExtras = new PersistableBundle(intentExtras);
             }
         }
-        mWeight = b.mWeight;
+        mRank = b.mRank;
         mExtras = b.mExtras;
         updateTimestamp();
     }
@@ -204,7 +233,10 @@
      */
     public void enforceMandatoryFields() {
         Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
-        Preconditions.checkStringNotEmpty(mTitle, "Shortcut title must be provided");
+        Preconditions.checkNotNull(mActivity, "activity must be provided");
+        if (mTitle == null && mTitleResId == 0) {
+            throw new IllegalArgumentException("Shortcut title must be provided");
+        }
         Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
     }
 
@@ -222,7 +254,7 @@
         mIconResourceId = source.mIconResourceId;
 
         if ((cloneFlags & CLONE_REMOVE_NON_KEY_INFO) == 0) {
-            mActivityComponent = source.mActivityComponent;
+            mActivity = source.mActivity;
 
             if ((cloneFlags & CLONE_REMOVE_ICON) == 0) {
                 mIcon = source.mIcon;
@@ -230,13 +262,17 @@
             }
 
             mTitle = source.mTitle;
+            mTitleResId = source.mTitleResId;
             mText = source.mText;
+            mTextResId = source.mTextResId;
+            mDisabledMessage = source.mDisabledMessage;
+            mDisabledMessageResId = source.mDisabledMessageResId;
             mCategories = clone(source.mCategories);
             if ((cloneFlags & CLONE_REMOVE_INTENT) == 0) {
                 mIntent = source.mIntent;
                 mIntentPersistableExtras = source.mIntentPersistableExtras;
             }
-            mWeight = source.mWeight;
+            mRank = source.mRank;
             mExtras = source.mExtras;
         } else {
             // Set this bit.
@@ -244,6 +280,30 @@
         }
     }
 
+    /** @hide */
+    public void resolveStringsRequiringCrossUser(Context context) throws NameNotFoundException {
+        mFlags |= FLAG_STRINGS_RESOLVED;
+
+        if ((mTitleResId == 0) && (mTextResId == 0) && (mDisabledMessageResId == 0)) {
+            return; // Bail early.
+        }
+        final Resources res = context.getPackageManager().getResourcesForApplicationAsUser(
+                mPackageName, mUserId);
+
+        if (mTitleResId != 0) {
+            mTitle = res.getString(mTitleResId);
+            mTitleResId = 0;
+        }
+        if (mTextResId != 0) {
+            mText = res.getString(mTextResId);
+            mTextResId = 0;
+        }
+        if (mDisabledMessageResId != 0) {
+            mDisabledMessage = res.getString(mDisabledMessageResId);
+            mDisabledMessageResId = 0;
+        }
+    }
+
     /**
      * Copy a {@link ShortcutInfo}, optionally removing fields.
      * @hide
@@ -253,6 +313,17 @@
     }
 
     /**
+     * @hide
+     */
+    public void ensureUpdatableWith(ShortcutInfo source) {
+        Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
+        Preconditions.checkState(mId.equals(source.mId), "ID must match");
+        Preconditions.checkState(mPackageName.equals(source.mPackageName),
+                "Package name must match");
+        Preconditions.checkState(!isImmutable(), "Target ShortcutInfo is immutable");
+    }
+
+    /**
      * Copy non-null/zero fields from another {@link ShortcutInfo}.  Only "public" information
      * will be overwritten.  The timestamp will be updated.
      *
@@ -260,16 +331,15 @@
      * - mBitmapPath will not change
      * - Current time will be set to timestamp
      *
+     * @throws IllegalStateException if source is not compatible.
+     *
      * @hide
      */
     public void copyNonNullFieldsFrom(ShortcutInfo source) {
-        Preconditions.checkState(mUserId == source.mUserId, "Owner User ID must match");
-        Preconditions.checkState(mId.equals(source.mId), "ID must match");
-        Preconditions.checkState(mPackageName.equals(source.mPackageName),
-                "Package name must match");
+        ensureUpdatableWith(source);
 
-        if (source.mActivityComponent != null) {
-            mActivityComponent = source.mActivityComponent;
+        if (source.mActivity != null) {
+            mActivity = source.mActivity;
         }
 
         if (source.mIcon != null) {
@@ -277,9 +347,24 @@
         }
         if (source.mTitle != null) {
             mTitle = source.mTitle;
+            mTitleResId = 0;
+        } else if (source.mTitleResId != 0) {
+            mTitle = null;
+            mTitleResId = source.mTitleResId;
         }
         if (source.mText != null) {
             mText = source.mText;
+            mTextResId = 0;
+        } else if (source.mTextResId != 0) {
+            mText = null;
+            mTextResId = source.mTextResId;
+        }
+        if (source.mDisabledMessage != null) {
+            mDisabledMessage = source.mDisabledMessage;
+            mDisabledMessageResId = 0;
+        } else if (source.mDisabledMessageResId != 0) {
+            mDisabledMessage = null;
+            mDisabledMessageResId = source.mDisabledMessageResId;
         }
         if (source.mCategories != null) {
             mCategories = clone(source.mCategories);
@@ -288,8 +373,8 @@
             mIntent = source.mIntent;
             mIntentPersistableExtras = source.mIntentPersistableExtras;
         }
-        if (source.mWeight != 0) {
-            mWeight = source.mWeight;
+        if (source.mRank != 0) {
+            mRank = source.mRank;
         }
         if (source.mExtras != null) {
             mExtras = source.mExtras;
@@ -310,7 +395,6 @@
                 throw getInvalidIconException();
         }
         if (icon.hasTint()) {
-            // TODO support it
             throw new IllegalArgumentException("Icons with tints are not supported");
         }
 
@@ -331,19 +415,27 @@
 
         private String mId;
 
-        private ComponentName mActivityComponent;
+        private ComponentName mActivity;
 
         private Icon mIcon;
 
-        private String mTitle;
+        private int mTitleResId;
 
-        private String mText;
+        private CharSequence mTitle;
+
+        private int mTextResId;
+
+        private CharSequence mText;
+
+        private int mDisabledMessageResId;
+
+        private CharSequence mDisabledMessage;
 
         private Set<String> mCategories;
 
         private Intent mIntent;
 
-        private int mWeight;
+        private int mRank;
 
         private PersistableBundle mExtras;
 
@@ -373,8 +465,8 @@
          * a hint to the launcher app about which launcher icon to associate this shortcut with.
          */
         @NonNull
-        public Builder setActivityComponent(@NonNull ComponentName activityComponent) {
-            mActivityComponent = Preconditions.checkNotNull(activityComponent, "activityComponent");
+        public Builder setActivity(@NonNull ComponentName activity) {
+            mActivity = Preconditions.checkNotNull(activity, "activity");
             return this;
         }
 
@@ -399,26 +491,88 @@
         }
 
         /**
-         * Sets the title of a shortcut.  This is a mandatory field.
+         * @hide We don't support resource strings for dynamic shortcuts for now.  (But unit tests
+         * use it.)
+         */
+        public Builder setShortLabelResId(int shortLabelResId) {
+            Preconditions.checkState(mTitle == null, "shortLabel already set");
+            mTitleResId = shortLabelResId;
+            return this;
+        }
+
+        /**
+         * Sets the short title of a shortcut.  This is a mandatory field.
          *
          * <p>This field is intended for a concise description of a shortcut displayed under
          * an icon.  The recommend max length is 10 characters.
          */
         @NonNull
-        public Builder setTitle(@NonNull String title) {
-            mTitle = Preconditions.checkStringNotEmpty(title, "title");
+        public Builder setShortLabel(@NonNull String shortLabel) {
+            Preconditions.checkState(mTitleResId == 0, "shortLabelResId already set");
+            mTitle = Preconditions.checkStringNotEmpty(shortLabel, "shortLabel");
+            return this;
+        }
+
+        /**
+         * @hide We don't support resource strings for dynamic shortcuts for now.  (But unit tests
+         * use it.)
+         */
+        public Builder setLongLabelResId(int longLabelResId) {
+            Preconditions.checkState(mText == null, "longLabel already set");
+            mTextResId = longLabelResId;
             return this;
         }
 
         /**
          * Sets the text of a shortcut.  This is an optional field.
          *
-         * <p>This field is intended to be more descriptive than the shortcut title.
+         * <p>This field is intended to be more descriptive than the shortcut title.  The launcher
+         * shows this instead of the short title, when it has enough space.
          * The recommend max length is 25 characters.
          */
         @NonNull
-        public Builder setText(@NonNull String text) {
-            mText = Preconditions.checkStringNotEmpty(text, "text");
+        public Builder setLongLabel(@NonNull String longLabel) {
+            Preconditions.checkState(mTextResId == 0, "longLabelResId already set");
+            mText = Preconditions.checkStringNotEmpty(longLabel, "longLabel");
+            return this;
+        }
+
+        /** @hide -- old signature, the internal code still uses it. */
+        public Builder setTitle(@NonNull String value) {
+            return setShortLabel(value);
+        }
+
+        /** @hide -- old signature, the internal code still uses it. */
+        public Builder setTitleResId(int value) {
+            return setShortLabelResId(value);
+        }
+
+        /** @hide -- old signature, the internal code still uses it. */
+        public Builder setText(@NonNull String value) {
+            return setLongLabel(value);
+        }
+
+        /** @hide -- old signature, the internal code still uses it. */
+        public Builder setTextResId(int value) {
+            return setLongLabelResId(value);
+        }
+
+        /**
+         * @hide We don't support resource strings for dynamic shortcuts for now.  (But unit tests
+         * use it.)
+         */
+        public Builder setDisabledMessageResId(int disabledMessageResId) {
+            Preconditions.checkState(mDisabledMessage == null, "disabledMessage already set");
+            mDisabledMessageResId = disabledMessageResId;
+            return this;
+        }
+
+        @NonNull
+        public Builder setDisabledMessage(@NonNull String disabledMessage) {
+            Preconditions.checkState(
+                    mDisabledMessageResId == 0, "disabledMessageResId already set");
+            mDisabledMessage =
+                    Preconditions.checkStringNotEmpty(disabledMessage, "disabledMessage");
             return this;
         }
 
@@ -441,16 +595,16 @@
         @NonNull
         public Builder setIntent(@NonNull Intent intent) {
             mIntent = Preconditions.checkNotNull(intent, "intent");
+            Preconditions.checkNotNull(mIntent.getAction(), "Intent action must be set.");
             return this;
         }
 
         /**
-         * Optionally sets the weight of a shortcut, which will be used by the launcher for sorting.
-         * The larger the weight, the more "important" a shortcut is.
+         * TODO javadoc.
          */
         @NonNull
-        public Builder setWeight(int weight) {
-            mWeight = weight;
+        public Builder setRank(int rank) {
+            mRank = rank;
             return this;
         }
 
@@ -485,7 +639,7 @@
      * Return the package name of the creator application.
      */
     @NonNull
-    public String getPackageName() {
+    public String getPackage() {
         return mPackageName;
     }
 
@@ -496,11 +650,11 @@
      * <p>This has nothing to do with the activity that this shortcut will launch.  This is
      * a hint to the launcher app that on which launcher icon this shortcut should be shown.
      *
-     * @see Builder#setActivityComponent
+     * @see Builder#setActivity
      */
     @Nullable
-    public ComponentName getActivityComponent() {
-        return mActivityComponent;
+    public ComponentName getActivity() {
+        return mActivity;
     }
 
     /**
@@ -517,25 +671,70 @@
         return mIcon;
     }
 
+    /** @hide -- old signature, the internal code still uses it. */
+    @Nullable
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /** @hide -- old signature, the internal code still uses it. */
+    public int getTitleResId() {
+        return mTitleResId;
+    }
+
+    /** @hide -- old signature, the internal code still uses it. */
+    @Nullable
+    public CharSequence getText() {
+        return mText;
+    }
+
+    /** @hide -- old signature, the internal code still uses it. */
+    public int getTextResId() {
+        return mTextResId;
+    }
+
     /**
-     * Return the shortcut title.
+     * Return the shorter version of the shortcut title.
      *
      * <p>All shortcuts must have a non-empty title, but this method will return null when
      * {@link #hasKeyFieldsOnly()} is true.
      */
     @Nullable
-    public String getTitle() {
+    public CharSequence getShortLabel() {
         return mTitle;
     }
 
+    /** TODO Javadoc */
+    public int getShortLabelResourceId() {
+        return mTitleResId;
+    }
+
     /**
      * Return the shortcut text.
      */
     @Nullable
-    public String getText() {
+    public CharSequence getLongLabel() {
         return mText;
     }
 
+    /** TODO Javadoc */
+    public int getLongLabelResourceId() {
+        return mTextResId;
+    }
+
+    /**
+     * Return the message that should be shown when a shortcut in disabled state is launched.
+     */
+    @Nullable
+    public CharSequence getDisabledMessage() {
+        return mDisabledMessage;
+    }
+
+    /** TODO Javadoc */
+    public int getDisabledMessageResourceId() {
+        return mDisabledMessageResId;
+    }
+
     /**
      * Return the categories.
      */
@@ -585,11 +784,10 @@
     }
 
     /**
-     * Return the weight of a shortcut, which will be used by Launcher for sorting.
-     * The larger the weight, the more "important" a shortcut is.
+     * TODO Javadoc
      */
-    public int getWeight() {
-        return mWeight;
+    public int getRank() {
+        return mRank;
     }
 
     /**
@@ -656,6 +854,68 @@
     }
 
     /**
+     * Return whether a shortcut is published via AndroidManifest.xml or not.  If {@code true},
+     * it's also {@link #isImmutable()}.
+     *
+     * <p>When an app is upgraded and a shortcut is no longer published from AndroidManifest.xml,
+     * this will be set to {@code false}.  If the shortcut is not pinned, then it'll just disappear.
+     * However, if it's pinned, it will still be alive, and {@link #isEnabled()} will be
+     * {@code false} and {@link #isImmutable()} will be {@code true}.
+     *
+     * <p>NOTE this is whether a shortcut is published from the <b>current version's</b>
+     * AndroidManifest.xml.
+     */
+    public boolean isManifestShortcut() {
+        return hasFlags(FLAG_MANIFEST);
+    }
+
+    /**
+     * @return true if pinned but neither dynamic nor manifest.
+     * @hide
+     */
+    public boolean isFloating() {
+        return isPinned() && !(isDynamic() || isManifestShortcut());
+    }
+
+    /** @hide */
+    public boolean isOriginallyFromManifest() {
+        return hasFlags(FLAG_IMMUTABLE);
+    }
+
+    /**
+     * Return if a shortcut is immutable, in which case it cannot be modified with any of
+     * {@link ShortcutManager} APIs.
+     *
+     * <p>All manifest shortcuts are immutable.  When a manifest shortcut is pinned and then
+     * disabled because the app is upgraded and its AndroidManifest.xml no longer publishes it,
+     * {@link #isManifestShortcut} returns {@code false}, but it is still immutable.
+     *
+     * <p>All shortcuts originally published via the {@link ShortcutManager} APIs
+     * are all mutable.
+     */
+    public boolean isImmutable() {
+        return hasFlags(FLAG_IMMUTABLE);
+    }
+
+    /**
+     * Returns {@code false} if a shortcut is disabled with
+     * {@link ShortcutManager#disableShortcuts}.
+     */
+    public boolean isEnabled() {
+        return !hasFlags(FLAG_DISABLED);
+    }
+
+    /** @hide */
+    public boolean isAlive() {
+        return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
+    }
+
+    /** @hide */
+    public boolean usesQuota() {
+        return hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST);
+    }
+
+    /**
      * Return whether a shortcut's icon is a resource in the owning package.
      *
      * @see LauncherApps#getShortcutIconResId(ShortcutInfo)
@@ -664,6 +924,16 @@
         return hasFlags(FLAG_HAS_ICON_RES);
     }
 
+    /** @hide */
+    public boolean hasStringResources() {
+        return (mTitleResId != 0) || (mTextResId != 0) || (mDisabledMessageResId != 0);
+    }
+
+    /** @hide */
+    public boolean hasAnyResources() {
+        return hasIconResource() || hasStringResources();
+    }
+
     /**
      * Return whether a shortcut's icon is stored as a file.
      *
@@ -678,7 +948,7 @@
      * following fields are available.
      * <ul>
      *     <li>{@link #getId()}
-     *     <li>{@link #getPackageName()}
+     *     <li>{@link #getPackage()}
      *     <li>{@link #getLastChangedTimestamp()}
      *     <li>{@link #isDynamic()}
      *     <li>{@link #isPinned()}
@@ -690,6 +960,11 @@
         return hasFlags(FLAG_KEY_FIELDS_ONLY);
     }
 
+    /** TODO Javadoc */
+    public boolean hasStringResourcesResolved() {
+        return hasFlags(FLAG_STRINGS_RESOLVED);
+    }
+
     /** @hide */
     public void updateTimestamp() {
         mLastChangedTimestamp = System.currentTimeMillis();
@@ -728,19 +1003,35 @@
         mBitmapPath = bitmapPath;
     }
 
+    /** @hide */
+    public void setDisabledMessageResId(int disabledMessageResId) {
+        mDisabledMessageResId = disabledMessageResId;
+        mDisabledMessage = null;
+    }
+
+    /** @hide */
+    public void setDisabledMessage(String disabledMessage) {
+        mDisabledMessage = disabledMessage;
+        mDisabledMessageResId = 0;
+    }
+
     private ShortcutInfo(Parcel source) {
         final ClassLoader cl = getClass().getClassLoader();
 
         mUserId = source.readInt();
         mId = source.readString();
         mPackageName = source.readString();
-        mActivityComponent = source.readParcelable(cl);
+        mActivity = source.readParcelable(cl);
         mIcon = source.readParcelable(cl);
-        mTitle = source.readString();
-        mText = source.readString();
+        mTitle = source.readCharSequence();
+        mTitleResId = source.readInt();
+        mText = source.readCharSequence();
+        mTextResId = source.readInt();
+        mDisabledMessage = source.readCharSequence();
+        mDisabledMessageResId = source.readInt();
         mIntent = source.readParcelable(cl);
         mIntentPersistableExtras = source.readParcelable(cl);
-        mWeight = source.readInt();
+        mRank = source.readInt();
         mExtras = source.readParcelable(cl);
         mLastChangedTimestamp = source.readLong();
         mFlags = source.readInt();
@@ -763,14 +1054,18 @@
         dest.writeInt(mUserId);
         dest.writeString(mId);
         dest.writeString(mPackageName);
-        dest.writeParcelable(mActivityComponent, flags);
+        dest.writeParcelable(mActivity, flags);
         dest.writeParcelable(mIcon, flags);
-        dest.writeString(mTitle);
-        dest.writeString(mText);
+        dest.writeCharSequence(mTitle);
+        dest.writeInt(mTitleResId);
+        dest.writeCharSequence(mText);
+        dest.writeInt(mTextResId);
+        dest.writeCharSequence(mDisabledMessage);
+        dest.writeInt(mDisabledMessageResId);
 
         dest.writeParcelable(mIntent, flags);
         dest.writeParcelable(mIntentPersistableExtras, flags);
-        dest.writeInt(mWeight);
+        dest.writeInt(mRank);
         dest.writeParcelable(mExtras, flags);
         dest.writeLong(mLastChangedTimestamp);
         dest.writeInt(mFlags);
@@ -823,24 +1118,58 @@
         sb.append("id=");
         sb.append(secure ? "***" : mId);
 
+        sb.append(", flags=0x");
+        sb.append(Integer.toHexString(mFlags));
+        sb.append(" [");
+        if (!isEnabled()) {
+            sb.append("X");
+        }
+        if (isImmutable()) {
+            sb.append("Im");
+        }
+        if (isManifestShortcut()) {
+            sb.append("M");
+        }
+        if (isDynamic()) {
+            sb.append("D");
+        }
+        if (isPinned()) {
+            sb.append("P");
+        }
+        if (hasIconFile()) {
+            sb.append("If");
+        }
+        if (hasIconResource()) {
+            sb.append("Ir");
+        }
+        if (hasKeyFieldsOnly()) {
+            sb.append("K");
+        }
+        if (hasStringResourcesResolved()) {
+            sb.append("Sr");
+        }
+        sb.append("]");
+
         sb.append(", packageName=");
         sb.append(mPackageName);
 
-        if (isDynamic()) {
-            sb.append(", dynamic");
-        }
-        if (isPinned()) {
-            sb.append(", pinned");
-        }
-
         sb.append(", activity=");
-        sb.append(mActivityComponent);
+        sb.append(mActivity);
 
-        sb.append(", title=");
+        sb.append(", shortLabel=");
         sb.append(secure ? "***" : mTitle);
+        sb.append(", resId=");
+        sb.append(mTitleResId);
 
-        sb.append(", text=");
+        sb.append(", longLabel=");
         sb.append(secure ? "***" : mText);
+        sb.append(", resId=");
+        sb.append(mTextResId);
+
+        sb.append(", disabledMessage=");
+        sb.append(secure ? "***" : mDisabledMessage);
+        sb.append(", resId=");
+        sb.append(mDisabledMessageResId);
 
         sb.append(", categories=");
         sb.append(mCategories);
@@ -848,8 +1177,8 @@
         sb.append(", icon=");
         sb.append(mIcon);
 
-        sb.append(", weight=");
-        sb.append(mWeight);
+        sb.append(", rank=");
+        sb.append(mRank);
 
         sb.append(", timestamp=");
         sb.append(mLastChangedTimestamp);
@@ -863,9 +1192,6 @@
         sb.append(", extras=");
         sb.append(mExtras);
 
-        sb.append(", flags=");
-        sb.append(mFlags);
-
         if (includeInternalData) {
 
             sb.append(", iconRes=");
@@ -881,22 +1207,27 @@
 
     /** @hide */
     public ShortcutInfo(
-            @UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
-            Icon icon, String title, String text, Set<String> categories, Intent intent,
-            PersistableBundle intentPersistableExtras,
-            int weight, PersistableBundle extras, long lastChangedTimestamp,
+            @UserIdInt int userId, String id, String packageName, ComponentName activity,
+            Icon icon, CharSequence title, int titleResId, CharSequence text, int textResId,
+            CharSequence disabledMessage, int disabledMessageResId, Set<String> categories,
+            Intent intent, PersistableBundle intentPersistableExtras,
+            int rank, PersistableBundle extras, long lastChangedTimestamp,
             int flags, int iconResId, String bitmapPath) {
         mUserId = userId;
         mId = id;
         mPackageName = packageName;
-        mActivityComponent = activityComponent;
+        mActivity = activity;
         mIcon = icon;
         mTitle = title;
+        mTitleResId = titleResId;
         mText = text;
+        mTextResId = textResId;
+        mDisabledMessage = disabledMessage;
+        mDisabledMessageResId = disabledMessageResId;
         mCategories = clone(categories);
         mIntent = intent;
         mIntentPersistableExtras = intentPersistableExtras;
-        mWeight = weight;
+        mRank = rank;
         mExtras = extras;
         mLastChangedTimestamp = lastChangedTimestamp;
         mFlags = flags;
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 16486e1..eaccb3a 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -17,8 +17,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.TestApi;
+import android.app.usage.UsageStatsManager;
 import android.content.Context;
-import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
@@ -29,14 +29,16 @@
 
 // TODO Enhance javadoc
 /**
+ * <b>TODO: Update to reflect DR changes, such as manifest shortcuts.</b><br>
+ *
  * {@link ShortcutManager} manages shortcuts created by applications.
  *
  * <h3>Dynamic shortcuts and pinned shortcuts</h3>
  *
  * An application can publish shortcuts with {@link #setDynamicShortcuts(List)} and
  * {@link #addDynamicShortcuts(List)}.  There can be at most
- * {@link #getMaxDynamicShortcutCount()} number of dynamic shortcuts at a time from the same
- * application.
+ * {@link #getMaxShortcutCountForActivity()} number of dynamic shortcuts at a time from the
+ * same application.
  * A dynamic shortcut can be deleted with {@link #removeDynamicShortcuts(List)}, and apps
  * can also use {@link #removeAllDynamicShortcuts()} to delete all dynamic shortcuts.
  *
@@ -50,7 +52,8 @@
  * <p>The number of pinned shortcuts does not affect the number of dynamic shortcuts that can be
  * published by an application at a time.
  * No matter how many pinned shortcuts that Launcher has for an application, the
- * application can still always publish {@link #getMaxDynamicShortcutCount()} number of dynamic
+ * application can still always publish {@link #getMaxShortcutCountForActivity()} number of
+ * dynamic
  * shortcuts.
  *
  * <h3>Shortcut IDs</h3>
@@ -80,16 +83,24 @@
  *
  * <h3>Backup and Restore</h3>
  *
- * Shortcuts will be backed up and restored across devices.  This means all information, including
- * IDs, must be meaningful on a different device.
+ * Pinned shortcuts will be backed up and restored across devices.  This means all information
+ * within shortcuts, including IDs, must be meaningful on different devices.
+ *
+ * <p>Note that:
+ * <ul>
+ *     <li>Dynamic shortcuts will not be backed up or restored.
+ *     <li>Icons of pinned shortcuts will <b>not</b> be backed up for performance reasons, unless
+ *     they refer to resources.  Instead, launcher applications are supposed to back up and restore
+ *     icons of pinned shortcuts by themselves, and thus from the user's point of view, pinned
+ *     shortcuts will look to have icons restored.
+ * </ul>
+ *
  *
  * <h3>APIs for launcher</h3>
  *
  * Launcher applications should use {@link LauncherApps} to get shortcuts that are published from
  * applications.  Launcher applications can also pin shortcuts with
  * {@link LauncherApps#pinShortcuts(String, List, UserHandle)}.
- *
- * @hide
  */
 public class ShortcutManager {
     private static final String TAG = "ShortcutManager";
@@ -123,7 +134,7 @@
      * @return {@code true} if the call has succeeded. {@code false} if the call is rate-limited.
      *
      * @throws IllegalArgumentException if {@code shortcutInfoList} contains more than
-     * {@link #getMaxDynamicShortcutCount()} shortcuts.
+     * {@link #getMaxShortcutCountForActivity()} shortcuts.
      */
     public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
         try {
@@ -136,7 +147,7 @@
 
     /**
      * Return all dynamic shortcuts from the caller application.  The number of result items
-     * will not exceed the value returned by {@link #getMaxDynamicShortcutCount()}.
+     * will not exceed the value returned by {@link #getMaxShortcutCountForActivity()}.
      */
     @NonNull
     public List<ShortcutInfo> getDynamicShortcuts() {
@@ -149,8 +160,21 @@
     }
 
     /**
-     * Publish a single dynamic shortcut.  If there's already dynamic or pinned shortcuts with
-     * the same ID, they will all be updated.
+     * TODO Javadoc
+     */
+    @NonNull
+    public List<ShortcutInfo> getManifestShortcuts() {
+        try {
+            return mService.getManifestShortcuts(mContext.getPackageName(), injectMyUserId())
+                    .getList();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Publish list of dynamic shortcuts.  If there's already dynamic or pinned shortcuts with
+     * the same IDs, they will all be updated.
      *
      * <p>This API will be rate-limited.
      *
@@ -169,7 +193,7 @@
     }
 
     /**
-     * Delete a single dynamic shortcut by ID.
+     * Delete dynamic shortcuts by ID.
      */
     public void removeDynamicShortcuts(@NonNull List<String> shortcutIds) {
         try {
@@ -221,9 +245,60 @@
     }
 
     /**
-     * Return the max number of dynamic shortcuts that each application can have at a time.
+     * TODO Javadoc
      */
-    public int getMaxDynamicShortcutCount() {
+    public void disableShortcuts(@NonNull List<String> shortcutIds) {
+        try {
+            mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+                    /* disabledMessage =*/ null, /* disabledMessageResId =*/ 0,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * TODO Javadoc
+     */
+    public void disableShortcuts(@NonNull List<String> shortcutIds, int disabledMessageResId) {
+        try {
+            mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+                    /* disabledMessage =*/ null, disabledMessageResId,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * TODO Javadoc
+     */
+    public void disableShortcuts(@NonNull List<String> shortcutIds, String disabledMessage) {
+        try {
+            mService.disableShortcuts(mContext.getPackageName(), shortcutIds,
+                    disabledMessage, /* disabledMessageResId =*/ 0,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * TODO Javadoc
+     */
+    public void enableShortcuts(@NonNull List<String> shortcutIds) {
+        try {
+            mService.enableShortcuts(mContext.getPackageName(), shortcutIds, injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Return the max number of dynamic shortcuts + manifest shortcuts that each launcehr icon
+     * can have at a time.
+     */
+    public int getMaxShortcutCountForActivity() {
         try {
             return mService.getMaxDynamicShortcutCount(mContext.getPackageName(), injectMyUserId());
         } catch (RemoteException e) {
@@ -260,16 +335,50 @@
     }
 
     /**
-     * Return the max width and height for icons, in pixels.
+     * Return the max width for icons, in pixels.
      */
-    public int getIconMaxDimensions() {
+    public int getIconMaxWidth() {
         try {
+            // TODO Implement it properly using xdpi.
             return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
     }
 
+    /**
+     * Return the max height for icons, in pixels.
+     */
+    public int getIconMaxHeight() {
+        try {
+            // TODO Implement it properly using ydpi.
+            return mService.getIconMaxDimensions(mContext.getPackageName(), injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Applications that publish shortcuts should call this method whenever an action that's
+     * equivalent to an existing shortcut has been taken by the user.  This includes not only when
+     * the user manually taps a shortcut, but when the user takes an equivalent action within the
+     * application -- for example, when a music player application has a shortcut to playlist X,
+     * then the application should not only report it when the playlist is opened from the
+     * shortcut, but also when the user plays the playlist within the application.
+     *
+     * <p>The information is accessible via {@link UsageStatsManager#queryEvents}
+     * Typically, launcher applications use this information to build a prediction model
+     * so that they can promote the shortcuts that are likely to be used at the moment.
+     */
+    public void reportShortcutUsed(String shortcutId) {
+        try {
+            mService.reportShortcutUsed(mContext.getPackageName(), shortcutId,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide injection point */
     @VisibleForTesting
     protected int injectMyUserId() {
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index dd3a36c..6cd8403 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -28,8 +28,8 @@
  */
 public class UserInfo implements Parcelable {
 
-    /** 8 bits for user type */
-    public static final int FLAG_MASK_USER_TYPE = 0x000000FF;
+    /** 16 bits for user type */
+    public static final int FLAG_MASK_USER_TYPE = 0x0000FFFF;
 
     /**
      * *************************** NOTE ***************************
@@ -87,6 +87,11 @@
      */
     public static final int FLAG_EPHEMERAL = 0x00000100;
 
+    /**
+     * User is for demo purposes only and can be removed at any time.
+     */
+    public static final int FLAG_DEMO = 0x00000200;
+
     public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
 
     public int id;
@@ -153,6 +158,10 @@
         return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED;
     }
 
+    public boolean isDemo() {
+        return (flags & FLAG_DEMO) == FLAG_DEMO;
+    }
+
     /**
      * Returns true if the user is a split system user.
      * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
diff --git a/core/java/android/hardware/camera2/CameraCaptureSession.java b/core/java/android/hardware/camera2/CameraCaptureSession.java
index 38279a4..4b21187 100644
--- a/core/java/android/hardware/camera2/CameraCaptureSession.java
+++ b/core/java/android/hardware/camera2/CameraCaptureSession.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.os.Handler;
 import android.view.Surface;
 
@@ -220,6 +221,53 @@
     public abstract void tearDown(@NonNull Surface surface) throws CameraAccessException;
 
     /**
+     * <p>
+     * Finish the deferred output configurations where the output Surface was not configured before.
+     * </p>
+     * <p>
+     * For camera use cases where a preview and other output configurations need to be configured,
+     * it can take some time for the preview Surface to be ready (e.g., if the preview Surface is
+     * obtained from {@link android.view.SurfaceView}, the SurfaceView is ready after the UI layout
+     * is done, then it takes some time to get the preview Surface).
+     * </p>
+     * <p>
+     * To speed up camera startup time, the application can configure the
+     * {@link CameraCaptureSession} with the desired preview size, and defer the preview output
+     * configuration until the Surface is ready. After the {@link CameraCaptureSession} is created
+     * successfully with this deferred configuration and other normal configurations, the
+     * application can submit requests that don't include deferred output Surfaces. Once the
+     * deferred Surface is ready, the application can set the Surface to the same deferred output
+     * configuration with the {@link OutputConfiguration#setDeferredSurface} method, and then finish
+     * the deferred output configuration via this method, before it can submit requests with this
+     * output target.
+     * </p>
+     * <p>
+     * The output Surfaces included by this list of deferred {@link OutputConfiguration
+     * OutputConfigurations} can be used as {@link CaptureRequest} targets as soon as this call
+     * returns;
+     * </p>
+     * <p>
+     * This method is not supported by Legacy devices.
+     * </p>
+     *
+     * @param deferredOutputConfigs a list of {@link OutputConfiguration OutputConfigurations} that
+     *            have had {@link OutputConfiguration#setDeferredSurface setDeferredSurface} invoked
+     *            with a valid output Surface.
+     * @throws CameraAccessException if the camera device is no longer connected or has encountered
+     *             a fatal error.
+     * @throws IllegalStateException if this session is no longer active, either because the session
+     *             was explicitly closed, a new session has been created or the camera device has
+     *             been closed. Or if this output configuration was already finished with the
+     *             included surface before.
+     * @throws IllegalArgumentException for invalid output configurations, including ones where the
+     *             source of the Surface is no longer valid or the Surface is from a unsupported
+     *             source.
+     * @hide
+     */
+    public abstract void finishDeferredConfiguration(
+            List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException;
+
+    /**
      * <p>Submit a request for an image to be captured by the camera device.</p>
      *
      * <p>The request defines all the parameters for capturing the single image,
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 6736d34..c23bd5b 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -24,6 +24,7 @@
 import android.hardware.camera2.dispatch.DuckTypingDispatcher;
 import android.hardware.camera2.dispatch.HandlerDispatcher;
 import android.hardware.camera2.dispatch.InvokeDispatcher;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.utils.TaskDrainer;
 import android.hardware.camera2.utils.TaskSingleDrainer;
 import android.os.Handler;
@@ -156,6 +157,12 @@
     }
 
     @Override
+    public void finishDeferredConfiguration(
+            List<OutputConfiguration> deferredOutputConfigs) throws CameraAccessException {
+        mDeviceImpl.finishDeferredConfig(deferredOutputConfigs);
+    }
+
+    @Override
     public synchronized int capture(CaptureRequest request, CaptureCallback callback,
             Handler handler) throws CameraAccessException {
         if (request == null) {
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 8cd1da5..1c8e124 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -21,6 +21,7 @@
 import android.hardware.camera2.CameraConstrainedHighSpeedCaptureSession;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.SurfaceUtils;
 import android.os.Handler;
@@ -256,6 +257,12 @@
         return mSessionImpl.isAborting();
     }
 
+    @Override
+    public void finishDeferredConfiguration(List<OutputConfiguration> deferredOutputConfigs)
+            throws CameraAccessException {
+        mSessionImpl.finishDeferredConfiguration(deferredOutputConfigs);
+    }
+
     private class WrapperCallback extends StateCallback {
         private final StateCallback mCallback;
 
@@ -263,26 +270,32 @@
             mCallback = callback;
         }
 
+        @Override
         public void onConfigured(CameraCaptureSession session) {
             mCallback.onConfigured(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
+        @Override
         public void onConfigureFailed(CameraCaptureSession session) {
             mCallback.onConfigureFailed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
+        @Override
         public void onReady(CameraCaptureSession session) {
             mCallback.onReady(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
+        @Override
         public void onActive(CameraCaptureSession session) {
             mCallback.onActive(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
+        @Override
         public void onClosed(CameraCaptureSession session) {
             mCallback.onClosed(CameraConstrainedHighSpeedCaptureSessionImpl.this);
         }
 
+        @Override
         public void onSurfacePrepared(CameraCaptureSession session, Surface surface) {
             mCallback.onSurfacePrepared(CameraConstrainedHighSpeedCaptureSessionImpl.this,
                     surface);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 5743b4d..e184d6d 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -407,7 +407,10 @@
                 int streamId = mConfiguredOutputs.keyAt(i);
                 OutputConfiguration outConfig = mConfiguredOutputs.valueAt(i);
 
-                if (!outputs.contains(outConfig)) {
+                if (!outputs.contains(outConfig) || outConfig.isDeferredConfiguration()) {
+                    // Always delete the deferred output configuration when the session
+                    // is created, as the deferred output configuration doesn't have unique surface
+                    // related identifies.
                     deleteList.add(streamId);
                 } else {
                     addSet.remove(outConfig);  // Don't create a stream previously created
@@ -744,6 +747,37 @@
         }
     }
 
+    public void finishDeferredConfig(List<OutputConfiguration> deferredConfigs)
+            throws CameraAccessException {
+        if (deferredConfigs == null || deferredConfigs.size() == 0) {
+            throw new IllegalArgumentException("deferred config is null or empty");
+        }
+
+        synchronized(mInterfaceLock) {
+            for (OutputConfiguration config : deferredConfigs) {
+                int streamId = -1;
+                for (int i = 0; i < mConfiguredOutputs.size(); i++) {
+                    // Have to use equal here, as createCaptureSessionByOutputConfigurations() and
+                    // createReprocessableCaptureSessionByConfigurations() do a copy of the configs.
+                    if (config.equals(mConfiguredOutputs.valueAt(i))) {
+                        streamId = mConfiguredOutputs.keyAt(i);
+                        break;
+                    }
+                }
+                if (streamId == -1) {
+                    throw new IllegalArgumentException("Deferred config is not part of this "
+                            + "session");
+                }
+
+                if (config.getSurface() == null) {
+                    throw new IllegalArgumentException("The deferred config for stream " + streamId
+                            + " must have a non-null surface");
+                }
+                mRemoteDevice.setDeferredConfiguration(streamId, config);
+            }
+        }
+    }
+
     public int capture(CaptureRequest request, CaptureCallback callback, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
@@ -2037,6 +2071,7 @@
      *
      * <p> Handle binder death for ICameraDeviceUser. Trigger onError.</p>
      */
+    @Override
     public void binderDied() {
         Log.w(TAG, "CameraDevice " + mCameraId + " died unexpectedly");
 
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
index ef5f6d7..d77f60b 100644
--- a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
+++ b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
@@ -215,5 +215,14 @@
         }
     }
 
+    public void setDeferredConfiguration(int streamId, OutputConfiguration deferredConfig)
+            throws CameraAccessException {
+        try {
+            mRemoteDevice.setDeferredConfiguration(streamId, deferredConfig);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
 
 }
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index acbf214..b9e75ee 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -567,6 +567,13 @@
     }
 
     @Override
+    public void setDeferredConfiguration(int steamId, OutputConfiguration config) {
+        String err = "Set deferred configuration is not supported on legacy devices";
+        Log.e(TAG, err);
+        throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
+    }
+
+    @Override
     public int createInputStream(int width, int height, int format) {
         String err = "Creating input stream is not supported on legacy devices";
         Log.e(TAG, err);
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index 61b534b..69c00e9 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -20,6 +20,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.hardware.camera2.utils.SurfaceUtils;
@@ -95,6 +97,21 @@
     }
 
     /**
+     * Unknown surface source type.
+     */
+    private final int SURFACE_TYPE_UNKNOWN = -1;
+
+    /**
+     * The surface is obtained from {@link android.view.SurfaceView}.
+     */
+    private final int SURFACE_TYPE_SURFACE_VIEW = 0;
+
+    /**
+     * The surface is obtained from {@link android.graphics.SurfaceTexture}.
+     */
+    private final int SURFACE_TYPE_SURFACE_TEXTURE = 1;
+
+    /**
      * Create a new {@link OutputConfiguration} instance with a {@link Surface},
      * with a surface group ID.
      *
@@ -179,12 +196,110 @@
         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;
+    }
+
+    /**
+     * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
+     * source class.
+     * <p>
+     * This constructor takes an argument for desired Surface size and the Surface source class
+     * without providing the actual output Surface. This is used to setup a output configuration
+     * with a deferred Surface. The application can use this output configuration to create a
+     * session.
+     * </p>
+     * <p>
+     * However, the actual output Surface must be set via {@link #setDeferredSurface} and finish the
+     * deferred Surface configuration via {@link CameraCaptureSession#finishDeferredConfiguration}
+     * before submitting a request with this Surface target. The deferred Surface can only be
+     * obtained from either from {@link android.view.SurfaceView} by calling
+     * {@link android.view.SurfaceHolder#getSurface}, or from
+     * {@link android.graphics.SurfaceTexture} via
+     * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}).
+     * </p>
+     *
+     * @param surfaceSize Size for the deferred surface.
+     * @param klass a non-{@code null} {@link Class} object reference that indicates the source of
+     *            this surface. Only {@link android.view.SurfaceHolder SurfaceHolder.class} and
+     *            {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
+     * @hide
+     */
+    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");
+        }
+
+        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;
+    }
+
+    /**
+     * Check if this configuration has deferred configuration.
+     *
+     * <p>This will return true if the output configuration was constructed with surface deferred.
+     * It will return true even after the deferred surface is set later.</p>
+     *
+     * @return true if this configuration has deferred surface.
+     * @hide
+     */
+    public boolean isDeferredConfiguration() {
+        return mIsDeferredConfig;
+    }
+
+    /**
+     * Set the deferred surface to this OutputConfiguration.
+     *
+     * <p>
+     * The deferred surface must be obtained from either from {@link android.view.SurfaceView} by
+     * calling {@link android.view.SurfaceHolder#getSurface}, or from
+     * {@link android.graphics.SurfaceTexture} via
+     * {@link android.view.Surface#Surface(android.graphics.SurfaceTexture)}). After the deferred
+     * surface is set, the application must finish the deferred surface configuration via
+     * {@link CameraCaptureSession#finishDeferredConfiguration} before submitting a request with
+     * this surface target.
+     * </p>
+     *
+     * @param surface The deferred surface to be set.
+     * @throws IllegalArgumentException if the Surface is invalid.
+     * @throws IllegalStateException if a Surface was already set to this deferred
+     *         OutputConfiguration.
+     * @hide
+     */
+    public void setDeferredSurface(@NonNull Surface surface) {
+        checkNotNull(surface, "Surface must not be null");
+        if (mSurface != null) {
+            throw new IllegalStateException("Deferred surface is already set!");
+        }
+
+        // This will throw IAE is the surface was abandoned.
+        Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
+        if (!surfaceSize.equals(mConfiguredSize)) {
+            Log.w(TAG, "Deferred surface size " + surfaceSize +
+                    " is different with pre-configured size " + mConfiguredSize +
+                    ", the pre-configured size will be used.");
+        }
+
+        mSurface = surface;
     }
 
     /**
@@ -203,10 +318,12 @@
         this.mSurface = other.mSurface;
         this.mRotation = other.mRotation;
         this.mSurfaceGroupId = other.mSurfaceGroupId;
+        this.mSurfaceType = other.mSurfaceType;
         this.mConfiguredDataspace = other.mConfiguredDataspace;
         this.mConfiguredFormat = other.mConfiguredFormat;
         this.mConfiguredSize = other.mConfiguredSize;
         this.mConfiguredGenerationId = other.mConfiguredGenerationId;
+        this.mIsDeferredConfig = other.mIsDeferredConfig;
     }
 
     /**
@@ -215,16 +332,30 @@
     private OutputConfiguration(@NonNull Parcel source) {
         int rotation = source.readInt();
         int surfaceSetId = source.readInt();
+        int surfaceType = source.readInt();
+        int width = source.readInt();
+        int height = source.readInt();
         Surface surface = Surface.CREATOR.createFromParcel(source);
-        checkNotNull(surface, "Surface must not be null");
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
         mSurfaceGroupId = surfaceSetId;
         mSurface = surface;
         mRotation = rotation;
-        mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
-        mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
-        mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
-        mConfiguredGenerationId = mSurface.getGenerationId();
+        if (surface != null) {
+            mSurfaceType = SURFACE_TYPE_UNKNOWN;
+            mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
+            mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
+            mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
+            mConfiguredGenerationId = mSurface.getGenerationId();
+            mIsDeferredConfig = true;
+        } else {
+            mSurfaceType = surfaceType;
+            mConfiguredSize = new Size(width, height);
+            mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+            mConfiguredGenerationId = 0;
+            mConfiguredDataspace =
+                    StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+            mIsDeferredConfig = false;
+        }
     }
 
     /**
@@ -291,7 +422,12 @@
         }
         dest.writeInt(mRotation);
         dest.writeInt(mSurfaceGroupId);
-        mSurface.writeToParcel(dest, flags);
+        dest.writeInt(mSurfaceType);
+        dest.writeInt(mConfiguredSize.getWidth());
+        dest.writeInt(mConfiguredSize.getHeight());
+        if (mSurface != null) {
+            mSurface.writeToParcel(dest, flags);
+        }
     }
 
     /**
@@ -311,13 +447,20 @@
             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;
+            }
             return mRotation == other.mRotation &&
-                   mSurface == other.mSurface &&
-                   mConfiguredGenerationId == other.mConfiguredGenerationId &&
+                   iSSurfaceEqual&&
                    mConfiguredSize.equals(other.mConfiguredSize) &&
                    mConfiguredFormat == other.mConfiguredFormat &&
                    mConfiguredDataspace == other.mConfiguredDataspace &&
-                   mSurfaceGroupId == other.mSurfaceGroupId;
+                   mSurfaceGroupId == other.mSurfaceGroupId &&
+                   mSurfaceType == other.mSurfaceType &&
+                   mIsDeferredConfig == other.mIsDeferredConfig;
         }
         return false;
     }
@@ -327,15 +470,26 @@
      */
     @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
+        // surface is set.
+        if (mIsDeferredConfig) {
+            return HashCodeHelpers.hashCode(
+                    mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
+                    mSurfaceGroupId, mSurfaceType);
+        }
+
         return HashCodeHelpers.hashCode(
             mRotation, mSurface.hashCode(), mConfiguredGenerationId,
             mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
     }
 
     private static final String TAG = "OutputConfiguration";
-    private final Surface mSurface;
+    private Surface mSurface;
     private final int mRotation;
-    private int mSurfaceGroupId;
+    private final int mSurfaceGroupId;
+    // Surface source type, this is only used by the deferred surface configuration objects.
+    private final int mSurfaceType;
 
     // The size, format, and dataspace of the surface when OutputConfiguration is created.
     private final Size mConfiguredSize;
@@ -343,4 +497,6 @@
     private final int mConfiguredDataspace;
     // Surface generation ID to distinguish changes to Surface native internals
     private final int mConfiguredGenerationId;
+    // Flag indicating if this config has deferred surface.
+    private final boolean mIsDeferredConfig;
 }
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index f9a7d19..8f21b38 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -21,6 +21,7 @@
 
 import android.app.PendingIntent;
 import android.content.Context;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
@@ -476,6 +477,26 @@
     }
 
     /**
+     * Grants permission to specified package for USB device without showing system dialog.
+     * Only system components can call this function, as it requires the MANAGE_USB permission.
+     * @param device to request permissions for
+     * @param packageName of package to grant permissions
+     *
+     * {@hide}
+     */
+    public void grantPermission(UsbDevice device, String packageName) {
+        try {
+            int uid = mContext.getPackageManager()
+                .getPackageUidAsUser(packageName, mContext.getUserId());
+            mService.grantDevicePermission(device, uid);
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Package " + packageName + " not found.", e);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns true if the specified USB function is currently enabled when in device mode.
      * <p>
      * USB functions represent interfaces which are published to the host to access
diff --git a/core/java/android/net/NetworkMisc.java b/core/java/android/net/NetworkMisc.java
index 5511a24..69f50a2 100644
--- a/core/java/android/net/NetworkMisc.java
+++ b/core/java/android/net/NetworkMisc.java
@@ -52,6 +52,15 @@
     public boolean acceptUnvalidated;
 
     /**
+     * Set to avoid surfacing the "Sign in to network" notification.
+     * if carrier receivers/apps are registered to handle the carrier-specific provisioning
+     * procedure, a carrier specific provisioning notification will be placed.
+     * only one notification should be displayed. This field is set based on
+     * which notification should be used for provisioning.
+     */
+    public boolean provisioningNotificationDisabled;
+
+    /**
      * For mobile networks, this is the subscriber ID (such as IMSI).
      */
     public String subscriberId;
@@ -65,6 +74,7 @@
             explicitlySelected = nm.explicitlySelected;
             acceptUnvalidated = nm.acceptUnvalidated;
             subscriberId = nm.subscriberId;
+            provisioningNotificationDisabled = nm.provisioningNotificationDisabled;
         }
     }
 
@@ -79,6 +89,7 @@
         out.writeInt(explicitlySelected ? 1 : 0);
         out.writeInt(acceptUnvalidated ? 1 : 0);
         out.writeString(subscriberId);
+        out.writeInt(provisioningNotificationDisabled ? 1 : 0);
     }
 
     public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -89,6 +100,7 @@
             networkMisc.explicitlySelected = in.readInt() != 0;
             networkMisc.acceptUnvalidated = in.readInt() != 0;
             networkMisc.subscriberId = in.readString();
+            networkMisc.provisioningNotificationDisabled = in.readInt() != 0;
             return networkMisc;
         }
 
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 41ff9fd..783c25a 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -290,6 +290,7 @@
 
     // Guarded by NfcAdapter.class
     static boolean sIsInitialized = false;
+    static boolean sHasNfcFeature;
 
     // Final after first constructor, except for
     // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
@@ -435,42 +436,65 @@
     }
 
     /**
+     * Helper to check if this device is NFC HCE capable, by checking for
+     * FEATURE_NFC_HOST_CARD_EMULATION and/or FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
+     * but without using a context.
+     */
+    private static boolean hasNfcHceFeature() {
+        IPackageManager pm = ActivityThread.getPackageManager();
+        if (pm == null) {
+            Log.e(TAG, "Cannot get package manager, assuming no NFC feature");
+            return false;
+        }
+        try {
+            return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)
+                || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF, 0);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Package manager query failed, assuming no NFC feature", e);
+            return false;
+        }
+    }
+
+    /**
      * Returns the NfcAdapter for application context,
      * or throws if NFC is not available.
      * @hide
      */
     public static synchronized NfcAdapter getNfcAdapter(Context context) {
         if (!sIsInitialized) {
+            sHasNfcFeature = hasNfcFeature();
+            boolean hasHceFeature = hasNfcHceFeature();
             /* is this device meant to have NFC */
-            if (!hasNfcFeature()) {
+            if (!sHasNfcFeature && !hasHceFeature) {
                 Log.v(TAG, "this device does not have NFC support");
                 throw new UnsupportedOperationException();
             }
-
             sService = getServiceInterface();
             if (sService == null) {
                 Log.e(TAG, "could not retrieve NFC service");
                 throw new UnsupportedOperationException();
             }
-            try {
-                sTagService = sService.getNfcTagInterface();
-            } catch (RemoteException e) {
-                Log.e(TAG, "could not retrieve NFC Tag service");
-                throw new UnsupportedOperationException();
+            if (sHasNfcFeature) {
+                try {
+                    sTagService = sService.getNfcTagInterface();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "could not retrieve NFC Tag service");
+                    throw new UnsupportedOperationException();
+                }
             }
-
-            try {
-                sCardEmulationService = sService.getNfcCardEmulationInterface();
-            } catch (RemoteException e) {
-                Log.e(TAG, "could not retrieve card emulation service");
-                throw new UnsupportedOperationException();
-            }
-
-            try {
-                sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
-            } catch (RemoteException e) {
-                Log.e(TAG, "could not retrieve NFC-F card emulation service");
-                throw new UnsupportedOperationException();
+            if (hasHceFeature) {
+                try {
+                    sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "could not retrieve NFC-F card emulation service");
+                    throw new UnsupportedOperationException();
+                }
+                try {
+                    sCardEmulationService = sService.getNfcCardEmulationInterface();
+                } catch (RemoteException e) {
+                    Log.e(TAG, "could not retrieve card emulation service");
+                    throw new UnsupportedOperationException();
+                }
             }
 
             sIsInitialized = true;
@@ -838,8 +862,14 @@
      *
      * @param uris an array of Uri(s) to push over Android Beam
      * @param activity activity for which the Uri(s) will be pushed
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void setBeamPushUris(Uri[] uris, Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
@@ -914,8 +944,14 @@
      *
      * @param callback callback, or null to disable
      * @param activity activity for which the Uri(s) will be pushed
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
@@ -992,9 +1028,15 @@
      * @param activities optional additional activities, however we strongly recommend
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void setNdefPushMessage(NdefMessage message, Activity activity,
             Activity ... activities) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         int targetSdkVersion = getSdkVersion();
         try {
             if (activity == null) {
@@ -1024,6 +1066,11 @@
      */
     @SystemApi
     public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null) {
             throw new NullPointerException("activity cannot be null");
         }
@@ -1094,9 +1141,15 @@
      * @param activities optional additional activities, however we strongly recommend
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
             Activity ... activities) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         int targetSdkVersion = getSdkVersion();
         try {
             if (activity == null) {
@@ -1168,9 +1221,15 @@
      * @param activities optional additional activities, however we strongly recommend
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
             Activity activity, Activity ... activities) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         int targetSdkVersion = getSdkVersion();
         try {
             if (activity == null) {
@@ -1227,9 +1286,15 @@
      * @param techLists the tech lists used to perform matching for dispatching of the
      *      {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
      * @throws IllegalStateException if the Activity is not currently in the foreground
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void enableForegroundDispatch(Activity activity, PendingIntent intent,
             IntentFilter[] filters, String[][] techLists) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null || intent == null) {
             throw new NullPointerException();
         }
@@ -1263,8 +1328,14 @@
      *
      * @param activity the Activity to disable dispatch to
      * @throws IllegalStateException if the Activity has already been paused
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void disableForegroundDispatch(Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         ActivityThread.currentActivityThread().unregisterOnActivityPausedListener(activity,
                 mForegroundDispatchListener);
         disableForegroundDispatchInternal(activity, false);
@@ -1309,9 +1380,15 @@
      * @param callback the callback to be called when a tag is discovered
      * @param flags Flags indicating poll technologies and other optional parameters
      * @param extras Additional extras for configuring reader mode.
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
             Bundle extras) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
     }
 
@@ -1321,8 +1398,14 @@
      * all supported tag technologies.
      *
      * @param activity the Activity that currently has reader mode enabled
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public void disableReaderMode(Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         mNfcActivityManager.disableReaderMode(activity);
     }
 
@@ -1349,8 +1432,14 @@
      *
      * @param activity the current foreground Activity that has registered data to share
      * @return whether the Beam animation was successfully invoked
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public boolean invokeBeam(Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null) {
             throw new NullPointerException("activity may not be null.");
         }
@@ -1404,10 +1493,16 @@
      * @param activity foreground activity
      * @param message a NDEF Message to push over NFC
      * @throws IllegalStateException if the activity is not currently in the foreground
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      * @deprecated use {@link #setNdefPushMessage} instead
      */
     @Deprecated
     public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null || message == null) {
             throw new NullPointerException();
         }
@@ -1432,10 +1527,16 @@
      *
      * @param activity the Foreground activity
      * @throws IllegalStateException if the Activity has already been paused
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      * @deprecated use {@link #setNdefPushMessage} instead
      */
     @Deprecated
     public void disableForegroundNdefPush(Activity activity) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         if (activity == null) {
             throw new NullPointerException();
         }
@@ -1452,6 +1553,9 @@
      */
     @SystemApi
     public boolean enableNdefPush() {
+        if (!sHasNfcFeature) {
+            throw new UnsupportedOperationException();
+        }
         try {
             return sService.enableNdefPush();
         } catch (RemoteException e) {
@@ -1467,6 +1571,11 @@
      */
     @SystemApi
     public boolean disableNdefPush() {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         try {
             return sService.disableNdefPush();
         } catch (RemoteException e) {
@@ -1497,8 +1606,14 @@
      *
      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
      * @return true if NDEF Push feature is enabled
+     * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
      */
     public boolean isNdefPushEnabled() {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         try {
             return sService.isNdefPushEnabled();
         } catch (RemoteException e) {
@@ -1623,6 +1738,11 @@
     @SystemApi
     public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
                                        String[] tagTechnologies) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         // If there are no tag technologies, don't bother adding unlock handler
         if (tagTechnologies.length == 0) {
             return false;
@@ -1666,6 +1786,11 @@
      */
     @SystemApi
     public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
+        synchronized (NfcAdapter.class) {
+            if (!sHasNfcFeature) {
+                throw new UnsupportedOperationException();
+            }
+        }
         try {
             synchronized (mLock) {
                 if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index f6e8940..6af0678 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -324,6 +324,33 @@
     }
 
     /**
+     * Return preloads directory.
+     * <p>This directory may contain pre-loaded content such as
+     * {@link #getDataPreloadsDemoDirectory() demo videos} and
+     * {@link #getDataPreloadsAppsDirectory() APK files} .
+     * {@hide}
+     */
+    public static File getDataPreloadsDirectory() {
+        return new File(getDataDirectory(), "preloads");
+    }
+
+    /**
+     * @see #getDataPreloadsDirectory()
+     * {@hide}
+     */
+    public static File getDataPreloadsDemoDirectory() {
+        return new File(getDataPreloadsDirectory(), "demo");
+    }
+
+    /**
+     * @see #getDataPreloadsDirectory()
+     * {@hide}
+     */
+    public static File getDataPreloadsAppsDirectory() {
+        return new File(getDataPreloadsDirectory(), "apps");
+    }
+
+    /**
      * Return the primary shared/external storage directory. This directory may
      * not currently be accessible if it has been mounted by the user on their
      * computer, has been removed from the device, or some other problem has
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index b3cf710..9bbe8f9 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -57,14 +57,19 @@
     /**
      * Power hint:
      * Interaction: The user is interacting with the device. The corresponding data field must be
-     * the expected duration of the fling, or 0 if unknown.
+     * the expected duration of the interaction, or 0 if unknown.
      *
-     * Sustained Performance Mode: Enable/Disables Sustained Performance Mode.
+     * Sustained Performance Mode: The corresponding data field must be Enable/Disable
+     * Sustained Performance Mode.
+     *
+     * Launch: This is specific for activity launching. The corresponding data field must be
+     * the expected duration of the required boost, or 0 if unknown.
      *
      * These must be kept in sync with the values in hardware/libhardware/include/hardware/power.h
      */
     public static final int POWER_HINT_INTERACTION = 2;
     public static final int POWER_HINT_SUSTAINED_PERFORMANCE_MODE = 6;
+    public static final int POWER_HINT_LAUNCH = 8;
 
     public static String wakefulnessToString(int wakefulness) {
         switch (wakefulness) {
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 4abbf0e..acb24e1 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -570,18 +570,19 @@
      * @throws SecurityException if the current user is not allowed to wipe data.
      */
     public static void rebootWipeUserData(Context context) throws IOException {
-        rebootWipeUserData(context, false, context.getPackageName());
+        rebootWipeUserData(context, false /* shutdown */, context.getPackageName(),
+                false /* force */);
     }
 
     /** {@hide} */
     public static void rebootWipeUserData(Context context, String reason) throws IOException {
-        rebootWipeUserData(context, false, reason);
+        rebootWipeUserData(context, false /* shutdown */, reason, false /* force */);
     }
 
     /** {@hide} */
     public static void rebootWipeUserData(Context context, boolean shutdown)
             throws IOException {
-        rebootWipeUserData(context, shutdown, context.getPackageName());
+        rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */);
     }
 
     /**
@@ -595,6 +596,9 @@
      * @param shutdown  if true, the device will be powered down after
      *                  the wipe completes, rather than being rebooted
      *                  back to the regular system.
+     * @param reason    the reason for the wipe that is visible in the logs
+     * @param force     whether the {@link UserManager.DISALLOW_FACTORY_RESET} user restriction
+     *                  should be ignored
      *
      * @throws IOException  if writing the recovery command file
      * fails, or if the reboot itself fails.
@@ -602,10 +606,10 @@
      *
      * @hide
      */
-    public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
-            throws IOException {
+    public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
+            boolean force) throws IOException {
         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
+        if (!force && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
             throw new SecurityException("Wiping data is not allowed for this user.");
         }
         final ConditionVariable condition = new ConditionVariable();
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 7146448..9b0ef8e 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -789,7 +789,7 @@
      */
     public boolean isPrimaryUser() {
         UserInfo user = getUserInfo(UserHandle.myUserId());
-        return user != null ? user.isPrimary() : false;
+        return user != null && user.isPrimary();
     }
 
     /**
@@ -855,7 +855,19 @@
      */
     public boolean isGuestUser() {
         UserInfo user = getUserInfo(UserHandle.myUserId());
-        return user != null ? user.isGuest() : false;
+        return user != null && user.isGuest();
+    }
+
+    /**
+     * Checks if the calling app is running in a demo user.
+     * <p>
+     * Caller must hold the MANAGE_USERS permission.
+     * @return whether the caller is a demo user.
+     * @hide
+     */
+    public boolean isDemoUser() {
+        UserInfo user = getUserInfo(UserHandle.myUserId());
+        return user != null && user.isDemo();
     }
 
     /**
@@ -1973,6 +1985,10 @@
         if (!supportsMultipleUsers()) {
             return false;
         }
+        // If Demo Mode is on, don't show user switcher
+        if (isDeviceInDemoMode(mContext)) {
+            return false;
+        }
         List<UserInfo> users = getUsers(true);
         if (users == null) {
            return false;
@@ -1989,6 +2005,14 @@
     }
 
     /**
+     * @hide
+     */
+    public static boolean isDeviceInDemoMode(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                Settings.Global.DEVICE_DEMO_MODE, 0) > 0;
+    }
+
+    /**
      * Returns a serial number on this device for a given userHandle. User handles can be recycled
      * when deleting and creating users, but serial numbers are not reused until the device is wiped.
      * @param userHandle
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 485bbd1..968996f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -45,8 +45,11 @@
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
+import java.io.InputStreamReader;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -115,6 +118,10 @@
     public static final int FLAG_INCLUDE_INVISIBLE = 1 << 10;
 
     private static volatile IMountService sMountService = null;
+    private static final String INTERNAL_STORAGE_SIZE_PATH =
+            "/sys/block/mmcblk0/size";
+    private static final String INTERNAL_STORAGE_SECTOR_SIZE =
+            "/sys/block/mmcblk0/queue/hw_sector_size";
 
     private final Context mContext;
     private final ContentResolver mResolver;
@@ -903,6 +910,23 @@
         return getVolumeList(UserHandle.myUserId(), FLAG_REAL_STATE | FLAG_INCLUDE_INVISIBLE)[0];
     }
 
+    /** {@hide} */
+    public long getPrimaryStorageSize() {
+        final long numberBlocks = readLong(INTERNAL_STORAGE_SIZE_PATH);
+        final long sectorSize = readLong(INTERNAL_STORAGE_SECTOR_SIZE);
+        return numberBlocks * sectorSize;
+    }
+
+    private long readLong(String path) {
+        try (final FileInputStream fis = new FileInputStream(path);
+                final BufferedReader reader = new BufferedReader(new InputStreamReader(fis));) {
+            return Long.parseLong(reader.readLine());
+        } catch (Exception e) {
+            Slog.w("Could not read " + path, e);
+            return 0;
+        }
+    }
+
     /** @removed */
     public @NonNull StorageVolume[] getVolumeList() {
         return getVolumeList(mContext.getUserId(), 0);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 893eb37..fbd61cf3 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -179,6 +179,7 @@
          * <li>{@link #VOICEMAIL_TYPE}</li>
          * <li>{@link #REJECTED_TYPE}</li>
          * <li>{@link #BLOCKED_TYPE}</li>
+         * <li>{@link #ANSWERED_EXTERNALLY_TYPE}</li>
          * </ul>
          * </p>
          */
@@ -200,7 +201,6 @@
          * Call log type for a call which was answered on another device.  Used in situations where
          * a call rings on multiple devices simultaneously and it ended up being answered on a
          * device other than the current one.
-         * @hide
          */
         public static final int ANSWERED_EXTERNALLY_TYPE = 7;
 
@@ -214,10 +214,7 @@
         /** Call had video. */
         public static final int FEATURES_VIDEO = 0x1;
 
-        /**
-         * Call was pulled externally.
-         * @hide
-         */
+        /** Call was pulled externally. */
         public static final int FEATURES_PULLED_EXTERNALLY = 0x2;
 
         /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ab2506e..d558070 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1277,6 +1277,17 @@
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_WEBVIEW_SETTINGS = "android.settings.WEBVIEW_SETTINGS";
 
+    /**
+     * Activity Action: Show the Deletion Helper settings.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_DELETION_HELPER_SETTINGS
+            = "android.settings.DELETION_HELPER_SETTINGS";
+
     // End of Intent actions for Settings
 
     /**
@@ -6227,6 +6238,14 @@
                 "managed_profile_contact_remote_search";
 
         /**
+         * Whether or not the automatic storage manager is enabled and should run on the device.
+         *
+         * @hide
+         */
+        public static final String AUTOMATIC_STORAGE_MANAGER_ENABLED =
+                "automatic_storage_manager_enabled";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -8584,6 +8603,15 @@
         public static final String SAFE_BOOT_DISALLOWED = "safe_boot_disallowed";
 
         /**
+         * Whether this device is currently in retail demo mode. If true, device
+         * usage is severely limited.
+         * <p>
+         * Type: int (0 for false, 1 for true)
+         * @hide
+         */
+        public static final String DEVICE_DEMO_MODE = "device_demo_mode";
+
+        /**
          * Settings to backup. This is here so that it's in the same place as the settings
          * keys and easy to update.
          *
@@ -8982,6 +9010,15 @@
         public static final String ENABLE_CELLULAR_ON_BOOT = "enable_cellular_on_boot";
 
         /**
+         * Whether toggling OEM unlock is disallowed. If disallowed, it is not possible to enable or
+         * disable OEM unlock.
+         * <p>
+         * Type: int (0: allow OEM unlock setting. 1: disallow OEM unlock)
+         * @hide
+         */
+        public static final String OEM_UNLOCK_DISALLOWED = "oem_unlock_disallowed";
+
+        /**
          * The maximum allowed notification enqueue rate in Hertz.
          *
          * Should be a float, and includes both posts and updates.
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 6a3cc02..ab9e497 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.database.ContentObserver;
-import android.database.Cursor;
 import android.net.Uri;
 import android.provider.CallLog.Calls;
 import android.telecom.PhoneAccount;
@@ -107,6 +106,47 @@
     public static final String ACTION_SYNC_VOICEMAIL = "android.provider.action.SYNC_VOICEMAIL";
 
     /**
+     * Broadcast intent to inform a new visual voicemail SMS has been received. This intent will
+     * only be delivered to the voicemail client. The intent will have the following extra values:
+     *
+     * <ul>
+     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_TYPE}</em> - (String) The event type of the SMS. Common
+     *   values are "SYNC" or "STATUS"</li>
+     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_DATA}</em> - (Bundle) The fields sent by the SMS</li>
+     *   <li><em>{@link #EXTRA_VOICEMAIL_SMS_SUBID}</em> - (Integer) The subscription ID of the
+     *   phone account that received the SMS</li>
+     * </ul>
+     */
+    /** @hide */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_VOICEMAIL_SMS_RECEIVED =
+            "android.intent.action.VOICEMAIL_SMS_RECEIVED";
+
+    /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+     * event type of the SMS. Common values are "SYNC" or "STATUS"
+     */
+    /** @hide */
+    public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
+            "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
+
+    /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
+     * fields sent by the SMS
+     */
+    /** @hide */
+    public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
+            "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
+
+    /**
+     * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
+     * subscription ID of the phone account that received the SMS.
+     */
+    /** @hide */
+    public static final String EXTRA_VOICEMAIL_SMS_SUBID =
+            "com.android.voicemail.extra.VOICEMAIL_SMS_SUBID";
+
+    /**
      * Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
      * receiving package made this change.
      */
@@ -360,6 +400,20 @@
          */
         public static final String SOURCE_PACKAGE = SOURCE_PACKAGE_FIELD;
 
+        /**
+         * The type of the source, which determines how to interpret source-specific states.
+         * Typically this will be set to the same string as
+         * {@link android.telephony.CarrierConfigManager#KEY_VVM_TYPE_STRING}. For example,
+         * "vvm_type_omtp".
+         *
+         * <P>Type: TEXT</P>
+         *
+         * @see #CONFIGURATION_STATE
+         * @see #DATA_CHANNEL_STATE
+         * @see #NOTIFICATION_CHANNEL_STATE
+         */
+        public static final String SOURCE_TYPE = "source_type";
+
         // Note: Multiple entries may exist for a single source if they are differentiated by the
         // PHONE_ACCOUNT_* fields.
 
@@ -392,6 +446,10 @@
         public static final String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
         /**
          * The configuration state of the voicemail source.
+         *
+         * <P>Negative values are reserved to the source for source-specific states, see
+         * {@link #SOURCE_TYPE}
+         *
          * <P> Possible values:
          * {@link #CONFIGURATION_STATE_OK},
          * {@link #CONFIGURATION_STATE_NOT_CONFIGURED},
@@ -399,14 +457,7 @@
          * <P>Type: INTEGER</P>
          */
         public static final String CONFIGURATION_STATE = "configuration_state";
-        /**
-         * Value of {@link #CONFIGURATION_STATE} passed into
-         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
-         * {@link #CONFIGURATION_STATE} field is not to be changed
-         *
-         * @hide
-         */
-        public static final int CONFIGURATION_STATE_IGNORE = -1;
+
         /** Value of {@link #CONFIGURATION_STATE} to indicate an all OK configuration status. */
         public static final int CONFIGURATION_STATE_OK = 0;
         /**
@@ -424,6 +475,10 @@
         /**
          * The data channel state of the voicemail source. This the channel through which the source
          * pulls voicemail data from a remote server.
+         *
+         * <P>Negative values are reserved to the source for source-specific states, see
+         * {@link #SOURCE_TYPE}
+         *
          * <P> Possible values:
          * {@link #DATA_CHANNEL_STATE_OK},
          * {@link #DATA_CHANNEL_STATE_NO_CONNECTION}
@@ -431,14 +486,7 @@
          * <P>Type: INTEGER</P>
          */
         public static final String DATA_CHANNEL_STATE = "data_channel_state";
-        /**
-         * Value of {@link #DATA_CHANNEL_STATE} passed into
-         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
-         * {@link #DATA_CHANNEL_STATE} field is not to be changed
-         *
-         * @hide
-         */
-        public static final int DATA_CHANNEL_STATE_IGNORE = -1;
+
         /**
          *  Value of {@link #DATA_CHANNEL_STATE} to indicate that data channel is working fine.
          */
@@ -478,6 +526,10 @@
         /**
          * The notification channel state of the voicemail source. This is the channel through which
          * the source gets notified of new voicemails on the remote server.
+         *
+         * <P>Negative values are reserved to the source for source-specific states, see
+         * {@link #SOURCE_TYPE}
+         *
          * <P> Possible values:
          * {@link #NOTIFICATION_CHANNEL_STATE_OK},
          * {@link #NOTIFICATION_CHANNEL_STATE_NO_CONNECTION},
@@ -486,14 +538,7 @@
          * <P>Type: INTEGER</P>
          */
         public static final String NOTIFICATION_CHANNEL_STATE = "notification_channel_state";
-        /**
-         * Value of {@link #NOTIFICATION_CHANNEL_STATE} passed into
-         * {@link #setStatus(Context, PhoneAccountHandle, int, int, int)} to indicate that the
-         * {@link #NOTIFICATION_CHANNEL_STATE} field is not to be changed
-         *
-         * @hide
-         */
-        public static final int NOTIFICATION_CHANNEL_STATE_IGNORE = -1;
+
         /**
          * Value of {@link #NOTIFICATION_CHANNEL_STATE} to indicate that the notification channel is
          * working fine.
@@ -543,67 +588,5 @@
             return Status.CONTENT_URI.buildUpon()
                     .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
         }
-
-        /**
-         * A helper method to set the status of a voicemail source.
-         *
-         * @param context The context from the package calling the method. This will be the source.
-         * @param accountHandle The handle for the account the source is associated with.
-         * @param configurationState See {@link Status#CONFIGURATION_STATE}
-         * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
-         * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
-         *
-         * @hide
-         */
-        public static void setStatus(Context context, PhoneAccountHandle accountHandle,
-                int configurationState, int dataChannelState, int notificationChannelState) {
-            ContentValues values = new ContentValues();
-            values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
-                    accountHandle.getComponentName().flattenToString());
-            values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
-            if(configurationState != CONFIGURATION_STATE_IGNORE) {
-                values.put(Status.CONFIGURATION_STATE, configurationState);
-            }
-            if(dataChannelState != DATA_CHANNEL_STATE_IGNORE) {
-                values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
-            }
-            if(notificationChannelState != NOTIFICATION_CHANNEL_STATE_IGNORE) {
-                values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
-            }
-            ContentResolver contentResolver = context.getContentResolver();
-            Uri statusUri = buildSourceUri(context.getPackageName());
-            contentResolver.insert(statusUri, values);
-        }
-
-        /**
-         * A helper method to set the quota of a voicemail source. Unit is unspecified.
-         *
-         * @param context The context from the package calling the method. This will be the source.
-         * @param accountHandle The handle for the account the source is associated with.
-         * @param occupied See {@link Status#QUOTA_OCCUPIED}
-         * @param total See {@link Status#QUOTA_TOTAL}
-         *
-         * @hide
-         */
-        public static void setQuota(Context context, PhoneAccountHandle accountHandle, int occupied,
-                int total) {
-            if (occupied == QUOTA_UNAVAILABLE && total == QUOTA_UNAVAILABLE) {
-                return;
-            }
-            ContentValues values = new ContentValues();
-            values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
-                    accountHandle.getComponentName().flattenToString());
-            values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
-            if (occupied != QUOTA_UNAVAILABLE) {
-                values.put(Status.QUOTA_OCCUPIED,occupied);
-            }
-            if (total != QUOTA_UNAVAILABLE) {
-                values.put(Status.QUOTA_TOTAL,total);
-            }
-
-            ContentResolver contentResolver = context.getContentResolver();
-            Uri statusUri = buildSourceUri(context.getPackageName());
-            contentResolver.insert(statusUri, values);
-        }
     }
 }
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index a70c24d..b47e872 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -126,4 +126,13 @@
         mGid1 = in.readString();
         mGid2 = in.readString();
     }
+
+    /** @hide */
+    public interface MatchType {
+        int ALL = 0;
+        int SPN = 1;
+        int IMSI_PREFIX = 2;
+        int GID1 = 3;
+        int GID2 = 4;
+    }
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index de8133b..06d87f8 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -55,6 +55,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
 
 import java.io.FileDescriptor;
@@ -628,9 +629,9 @@
                     mCurWindowFlags = mWindowFlags;
                     mLayout.flags = mWindowFlags
                             | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
+                            | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
                             | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                            ;
+                            | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                     mCurWindowPrivateFlags = mWindowPrivateFlags;
                     mLayout.privateFlags = mWindowPrivateFlags;
 
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 636384c..599c9c72 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -796,8 +796,16 @@
     public static final int KEYCODE_COPY = 278;
     /** Key code constant: Paste key. */
     public static final int KEYCODE_PASTE = 279;
+    /** Key code constant: fingerprint navigation up */
+    public static final int KEYCODE_FP_NAV_UP = 280;
+    /** Key code constant: fingerprint navigation down */
+    public static final int KEYCODE_FP_NAV_DOWN = 281;
+    /** Key code constant: fingerprint navigation left*/
+    public static final int KEYCODE_FP_NAV_LEFT = 282;
+    /** Key code constant: fingerprint navigation right */
+    public static final int KEYCODE_FP_NAV_RIGHT = 283;
 
-    private static final int LAST_KEYCODE = KEYCODE_PASTE;
+    private static final int LAST_KEYCODE = KEYCODE_FP_NAV_RIGHT;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -1844,6 +1852,10 @@
             case KeyEvent.KEYCODE_BRIGHTNESS_DOWN:
             case KeyEvent.KEYCODE_BRIGHTNESS_UP:
             case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
+            case KeyEvent.KEYCODE_FP_NAV_UP:
+            case KeyEvent.KEYCODE_FP_NAV_DOWN:
+            case KeyEvent.KEYCODE_FP_NAV_LEFT:
+            case KeyEvent.KEYCODE_FP_NAV_RIGHT:
                 return true;
         }
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 6dc5ff7..4a0f350 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -3176,7 +3176,9 @@
         // we don't add a filter to the static version returned by getSystemService.
         inflater = inflater.cloneInContext(inflationContext);
         inflater.setFilter(this);
-        return inflater.inflate(rv.getLayoutId(), parent, false);
+        View v = inflater.inflate(rv.getLayoutId(), parent, false);
+        v.setTagInternal(R.id.widget_frame, rv.getLayoutId());
+        return v;
     }
 
     private static void loadTransitionOverride(Context context,
@@ -3354,7 +3356,7 @@
         // across orientation change, and has the RemoteViews re-applied in the new orientation,
         // we throw an exception, since the layouts may be completely unrelated.
         if (hasLandscapeAndPortraitLayouts()) {
-            if (v.getId() != rvToApply.getLayoutId()) {
+            if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) {
                 throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
                         " that does not share the same root layout id.");
             }
@@ -3390,7 +3392,7 @@
         // across orientation change, and has the RemoteViews re-applied in the new orientation,
         // we throw an exception, since the layouts may be completely unrelated.
         if (hasLandscapeAndPortraitLayouts()) {
-            if (v.getId() != rvToApply.getLayoutId()) {
+            if ((Integer) v.getTag(R.id.widget_frame) != rvToApply.getLayoutId()) {
                 throw new RuntimeException("Attempting to re-apply RemoteViews to a view that" +
                         " that does not share the same root layout id.");
             }
diff --git a/core/java/com/android/internal/app/AlertActivity.java b/core/java/com/android/internal/app/AlertActivity.java
index ed48b0d..35ffa71 100644
--- a/core/java/com/android/internal/app/AlertActivity.java
+++ b/core/java/com/android/internal/app/AlertActivity.java
@@ -49,7 +49,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        mAlert = new AlertController(this, this, getWindow());
+        mAlert = AlertController.create(this, this, getWindow());
         mAlertParams = new AlertController.AlertParams(this);
     }
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index b7ac600..c5ed29f 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -61,14 +61,15 @@
 import java.lang.ref.WeakReference;
 
 public class AlertController {
+    public static final int MICRO = 1;
 
     private final Context mContext;
     private final DialogInterface mDialogInterface;
-    private final Window mWindow;
+    protected final Window mWindow;
 
     private CharSequence mTitle;
-    private CharSequence mMessage;
-    private ListView mListView;
+    protected CharSequence mMessage;
+    protected ListView mListView;
     private View mView;
 
     private int mViewLayoutResId;
@@ -91,14 +92,14 @@
     private CharSequence mButtonNeutralText;
     private Message mButtonNeutralMessage;
 
-    private ScrollView mScrollView;
+    protected ScrollView mScrollView;
 
     private int mIconId = 0;
     private Drawable mIcon;
 
     private ImageView mIconView;
     private TextView mTitleView;
-    private TextView mMessageView;
+    protected TextView mMessageView;
     private View mCustomTitleView;
 
     private boolean mForceInverseBackground;
@@ -176,7 +177,21 @@
         return outValue.data != 0;
     }
 
-    public AlertController(Context context, DialogInterface di, Window window) {
+    public static final AlertController create(Context context, DialogInterface di, Window window) {
+        final TypedArray a = context.obtainStyledAttributes(
+                null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
+        int controllerType = a.getInt(R.styleable.AlertDialog_controllerType, 0);
+        a.recycle();
+
+        switch (controllerType) {
+            case MICRO:
+                return new MicroAlertController(context, di, window);
+            default:
+                return new AlertController(context, di, window);
+        }
+    }
+
+    protected AlertController(Context context, DialogInterface di, Window window) {
         mContext = context;
         mDialogInterface = di;
         mWindow = window;
@@ -643,7 +658,7 @@
         }
     }
 
-    private void setupContent(ViewGroup contentPanel) {
+    protected void setupContent(ViewGroup contentPanel) {
         mScrollView = (ScrollView) contentPanel.findViewById(R.id.scrollView);
         mScrollView.setFocusable(false);
 
@@ -871,8 +886,8 @@
             listView.setAdapter(mAdapter);
             final int checkedItem = mCheckedItem;
             if (checkedItem > -1) {
-                listView.setItemChecked(checkedItem, true);
-                listView.setSelection(checkedItem);
+                listView.setItemChecked(checkedItem + listView.getHeaderViewsCount(), true);
+                listView.setSelection(checkedItem + listView.getHeaderViewsCount());
             }
         }
     }
@@ -1051,7 +1066,8 @@
                             if (mCheckedItems != null) {
                                 boolean isItemChecked = mCheckedItems[position];
                                 if (isItemChecked) {
-                                    listView.setItemChecked(position, true);
+                                    listView.setItemChecked(
+                                            position + listView.getHeaderViewsCount(), true);
                                 }
                             }
                             return view;
@@ -1072,7 +1088,8 @@
                         public void bindView(View view, Context context, Cursor cursor) {
                             CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);
                             text.setText(cursor.getString(mLabelIndex));
-                            listView.setItemChecked(cursor.getPosition(),
+                            listView.setItemChecked(
+                                    cursor.getPosition() + listView.getHeaderViewsCount(),
                                     cursor.getInt(mIsCheckedIndex) == 1);
                         }
 
@@ -1116,6 +1133,7 @@
                 listView.setOnItemClickListener(new OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                        position -= listView.getHeaderViewsCount();
                         mOnClickListener.onClick(dialog.mDialogInterface, position);
                         if (!mIsSingleChoice) {
                             dialog.mDialogInterface.dismiss();
@@ -1126,6 +1144,7 @@
                 listView.setOnItemClickListener(new OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
+                        position -= listView.getHeaderViewsCount();
                         if (mCheckedItems != null) {
                             mCheckedItems[position] = listView.isItemChecked(position);
                         }
diff --git a/core/java/com/android/internal/app/MicroAlertController.java b/core/java/com/android/internal/app/MicroAlertController.java
new file mode 100644
index 0000000..085b226
--- /dev/null
+++ b/core/java/com/android/internal/app/MicroAlertController.java
@@ -0,0 +1,85 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.AbsListView;
+
+import com.android.internal.app.AlertController;
+import com.android.internal.R;
+
+public class MicroAlertController extends AlertController {
+    public MicroAlertController(Context context, DialogInterface di, Window window) {
+        super(context, di, window);
+    }
+
+    @Override
+    protected void setupContent(ViewGroup contentPanel) {
+        // Special case for small screen - the scroll view is higher in hierarchy
+        mScrollView = (ScrollView) mWindow.findViewById(R.id.scrollView);
+
+        // Special case for users that only want to display a String
+        mMessageView = (TextView) contentPanel.findViewById(R.id.message);
+        if (mMessageView == null) {
+            return;
+        }
+
+        if (mMessage != null) {
+            mMessageView.setText(mMessage);
+        } else {
+            // no message, remove associated views
+            mMessageView.setVisibility(View.GONE);
+            contentPanel.removeView(mMessageView);
+
+            if (mListView != null) {
+                // has ListView, swap ScrollView with ListView
+
+                // move topPanel into header of ListView
+                View topPanel = mScrollView.findViewById(R.id.topPanel);
+                ((ViewGroup) topPanel.getParent()).removeView(topPanel);
+                topPanel.setLayoutParams(
+                        new AbsListView.LayoutParams(topPanel.getLayoutParams()));
+                mListView.addHeaderView(topPanel, null, false);
+
+                // move buttonPanel into footer of ListView
+                View buttonPanel = mScrollView.findViewById(R.id.buttonPanel);
+                ((ViewGroup) buttonPanel.getParent()).removeView(buttonPanel);
+                buttonPanel.setLayoutParams(
+                        new AbsListView.LayoutParams(buttonPanel.getLayoutParams()));
+                mListView.addFooterView(buttonPanel, null, false);
+
+                // swap ScrollView w/ ListView
+                final ViewGroup scrollParent = (ViewGroup) mScrollView.getParent();
+                final int childIndex = scrollParent.indexOfChild(mScrollView);
+                scrollParent.removeViewAt(childIndex);
+                scrollParent.addView(mListView, childIndex,
+                        new ViewGroup.LayoutParams(
+                                ViewGroup.LayoutParams.MATCH_PARENT,
+                                ViewGroup.LayoutParams.MATCH_PARENT));
+            } else {
+                // no content, just hide everything
+                contentPanel.setVisibility(View.GONE);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 085e159..0a4ac0d 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -69,9 +69,13 @@
 import android.widget.ListView;
 import android.widget.TextView;
 import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto;
 import com.android.internal.widget.ResolverDrawerLayout;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -359,6 +363,12 @@
         if (isVoiceInteraction()) {
             onSetupVoiceInteraction();
         }
+        final Set<String> categories = intent.getCategories();
+        MetricsLogger.action(this, mAdapter.hasFilteredItem()
+                ? MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_APP_FEATURED
+                : MetricsProto.MetricsEvent.ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED,
+                intent.getAction() + ":" + intent.getType() + ":"
+                        + (categories != null ? Arrays.toString(categories.toArray()) : ""));
     }
 
     public final void setFilteredComponents(ComponentName[] components) {
@@ -649,6 +659,19 @@
 
         TargetInfo target = mAdapter.targetInfoForPosition(which, filtered);
         if (onTargetSelected(target, always)) {
+            if (always && filtered) {
+                MetricsLogger.action(
+                        this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_ALWAYS);
+            } else if (filtered) {
+                MetricsLogger.action(
+                        this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_JUST_ONCE);
+            } else {
+                MetricsLogger.action(
+                        this, MetricsProto.MetricsEvent.ACTION_APP_DISAMBIG_TAP);
+            }
+            MetricsLogger.action(this, mAdapter.hasFilteredItem()
+                            ? MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_APP_FEATURED
+                            : MetricsProto.MetricsEvent.ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED);
             finish();
         }
     }
diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
index 4260e50..951a45a 100644
--- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
+++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl
@@ -34,7 +34,7 @@
     // for AppWidgetHost
     //
     ParceledListSlice startListening(IAppWidgetHost host, String callingPackage, int hostId,
-            in int[] appWidgetIds, out int[] updatedIds);
+            in int[] appWidgetIds);
     void stopListening(String callingPackage, int hostId);
     int allocateAppWidgetId(String callingPackage, int hostId);
     void deleteAppWidgetId(String callingPackage, int appWidgetId);
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
index 2653745..7d222c7 100644
--- a/core/java/com/android/internal/util/WakeupMessage.java
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -45,24 +45,32 @@
     protected final String mCmdName;
     @VisibleForTesting
     protected final int mCmd, mArg1, mArg2;
+    @VisibleForTesting
+    protected final Object mObj;
     private boolean mScheduled;
 
     public WakeupMessage(Context context, Handler handler,
-            String cmdName, int cmd, int arg1, int arg2) {
+            String cmdName, int cmd, int arg1, int arg2, Object obj) {
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mHandler = handler;
         mCmdName = cmdName;
         mCmd = cmd;
         mArg1 = arg1;
         mArg2 = arg2;
+        mObj = obj;
     }
 
     public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
-        this(context, handler, cmdName, cmd, arg1, 0);
+        this(context, handler, cmdName, cmd, arg1, 0, null);
+    }
+
+    public WakeupMessage(Context context, Handler handler,
+            String cmdName, int cmd, int arg1, int arg2) {
+        this(context, handler, cmdName, cmd, arg1, arg2, null);
     }
 
     public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
-        this(context, handler, cmdName, cmd, 0, 0);
+        this(context, handler, cmdName, cmd, 0, 0, null);
     }
 
     /**
@@ -99,7 +107,7 @@
             mScheduled = false;
         }
         if (stillScheduled) {
-            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2, mObj);
             mHandler.handleMessage(msg);
             msg.recycle();
         }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 6c289dc..b2028a7 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -481,6 +481,8 @@
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
 
+    <protected-broadcast android:name="com.android.server.am.ACTION_RESET_DEMO" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
diff --git a/core/res/res/layout-notround/alert_dialog_header_micro.xml b/core/res/res/layout-notround/alert_dialog_header_micro.xml
new file mode 100644
index 0000000..fc840d9
--- /dev/null
+++ b/core/res/res/layout-notround/alert_dialog_header_micro.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="top|center_horizontal"
+        android:minHeight="@dimen/alert_dialog_title_height">
+    <ImageView android:id="@+id/icon"
+            android:maxHeight="24dp"
+            android:maxWidth="24dp"
+            android:layout_marginTop="8dp"
+            android:layout_marginStart="8dp"
+            android:layout_marginBottom="8dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@null" />
+    <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+            style="?android:attr/windowTitleStyle"
+            android:ellipsize="end"
+            android:layout_marginStart="8dp"
+            android:layout_marginBottom="8dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="viewStart" />
+</LinearLayout>
diff --git a/core/res/res/layout-round/alert_dialog_header_micro.xml b/core/res/res/layout-round/alert_dialog_header_micro.xml
new file mode 100644
index 0000000..6f7ae02
--- /dev/null
+++ b/core/res/res/layout-round/alert_dialog_header_micro.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="top|center_horizontal"
+        android:minHeight="@dimen/alert_dialog_title_height">
+    <ImageView android:id="@+id/icon"
+            android:maxHeight="24dp"
+            android:maxWidth="24dp"
+            android:layout_marginTop="12dp"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:src="@null" />
+    <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
+            style="?android:attr/windowTitleStyle"
+            android:ellipsize="end"
+            android:layout_marginTop="36dp"
+            android:layout_marginBottom="4dp"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="center" />
+</FrameLayout>
diff --git a/core/res/res/layout-watch/input_method_extract_view.xml b/core/res/res/layout-watch/input_method_extract_view.xml
index e3cd2ce..de4ca69 100644
--- a/core/res/res/layout-watch/input_method_extract_view.xml
+++ b/core/res/res/layout-watch/input_method_extract_view.xml
@@ -34,7 +34,6 @@
         android:textColor="@color/primary_text_default_material_dark"
         android:textColorHighlight="@color/accent_material_dark"
         android:textSize="18dp"
-        android:cursorVisible="false"
         android:gravity="bottom|right"
         />
 
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout/alert_dialog_micro.xml
index abdbd16..04f8a2a 100644
--- a/core/res/res/layout/alert_dialog_micro.xml
+++ b/core/res/res/layout/alert_dialog_micro.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ 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,127 +14,100 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-
-<LinearLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/parentPanel"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:background="@android:color/white"
-    android:layout_gravity="center"
-    android:orientation="vertical">
-
-    <LinearLayout android:id="@+id/topPanel"
+<FrameLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/parentPanel"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:orientation="vertical">
-        <View android:id="@+id/titleDividerTop"
+        android:layout_height="match_parent">
+    <ScrollView
+            android:id="@+id/scrollView"
             android:layout_width="match_parent"
-            android:layout_height="2dip"
-            android:visibility="gone"
-            android:background="@android:color/holo_blue_light" />
-        <LinearLayout android:id="@+id/title_template"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:gravity="center_vertical|start"
-            android:minHeight="@dimen/alert_dialog_title_height"
-            android:layout_marginStart="16dip"
-            android:layout_marginEnd="16dip">
-            <ImageView android:id="@+id/icon"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingEnd="8dip"
-                android:src="@null" />
-            <com.android.internal.widget.DialogTitle android:id="@+id/alertTitle"
-                style="?android:attr/windowTitleStyle"
-                android:singleLine="true"
-                android:ellipsize="end"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:textAlignment="viewStart" />
-        </LinearLayout>
-        <View android:id="@+id/titleDivider"
-            android:layout_width="match_parent"
-            android:layout_height="2dip"
-            android:visibility="gone"
-            android:background="@android:color/holo_blue_light" />
-        <!-- If the client uses a customTitle, it will be added here. -->
-    </LinearLayout>
-
-    <LinearLayout android:id="@+id/contentPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:orientation="vertical"
-        android:minHeight="64dp">
-        <ScrollView android:id="@+id/scrollView"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:clipToPadding="false">
-            <TextView android:id="@+id/message"
-                style="?android:attr/textAppearanceMedium"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:paddingStart="16dip"
-                android:paddingEnd="16dip"
-                android:paddingTop="8dip"
-                android:paddingBottom="8dip"/>
-        </ScrollView>
-    </LinearLayout>
-
-    <FrameLayout android:id="@+id/customPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_weight="1"
-        android:minHeight="64dp">
-        <FrameLayout android:id="@+android:id/custom"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content" />
-    </FrameLayout>
-
-    <LinearLayout android:id="@+id/buttonPanel"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:minHeight="@dimen/alert_dialog_button_bar_height"
-        android:orientation="vertical"
-        android:divider="?android:attr/dividerHorizontal"
-        android:showDividers="beginning"
-        android:dividerPadding="0dip">
+            android:layout_height="match_parent">
         <LinearLayout
-            style="?android:attr/buttonBarStyle"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="horizontal"
-            android:layoutDirection="locale"
-            android:measureWithLargestChild="true">
-            <Button android:id="@+id/button2"
-                android:layout_width="wrap_content"
-                android:layout_gravity="start"
-                android:layout_weight="1"
-                android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
-            <Button android:id="@+id/button3"
-                android:layout_width="wrap_content"
-                android:layout_gravity="center_horizontal"
-                android:layout_weight="1"
-                android:maxLines="2"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content" />
-            <Button android:id="@+id/button1"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:layout_weight="1"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarButtonStyle"
-                android:textSize="14sp"
-                android:layout_height="wrap_content" />
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content">
+            <!-- Top Panel -->
+            <FrameLayout
+                    android:paddingLeft="@dimen/dialog_padding_micro"
+                    android:paddingRight="@dimen/dialog_padding_micro"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:id="@+id/topPanel">
+                <include android:id="@+id/title_template"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        layout="@layout/alert_dialog_header_micro"/>
+            </FrameLayout>
+
+            <!-- Content Panel -->
+            <FrameLayout android:id="@+id/contentPanel"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:clipToPadding="false">
+                <TextView android:id="@+id/message"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:textAppearance="@style/TextAppearance.Micro.AlertDialog.Message"
+                        android:paddingStart="@dimen/dialog_padding_micro"
+                        android:paddingEnd="@dimen/dialog_padding_micro"
+                        android:paddingTop="8dip"
+                        android:paddingBottom="8dip"/>
+            </FrameLayout>
+
+            <!-- Custom Panel, to replace content panel if needed -->
+            <FrameLayout android:id="@+id/customPanel"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:minHeight="64dp">
+                <FrameLayout android:id="@+android:id/custom"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content" />
+            </FrameLayout>
+
+            <!-- Button Panel -->
+            <FrameLayout
+                    android:id="@+id/buttonPanel"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content">
+                <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:divider="?android:attr/dividerHorizontal"
+                        android:showDividers="beginning"
+                        android:dividerPadding="0dip"
+                        android:orientation="vertical"
+                        android:minHeight="@dimen/alert_dialog_button_bar_height"
+                        android:paddingBottom="@dimen/dialog_padding_micro"
+                        style="?android:attr/buttonBarStyle"
+                        android:layoutDirection="locale"
+                        android:measureWithLargestChild="true">
+                    <Button android:id="@+id/button1"
+                            android:layout_gravity="start"
+                            android:layout_weight="1"
+                            android:layout_marginLeft="@dimen/dialog_padding_micro"
+                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            style="?android:attr/buttonBarButtonStyle"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content" />
+                    <Button android:id="@+id/button3"
+                            android:layout_gravity="start"
+                            android:layout_weight="1"
+                            android:layout_marginLeft="@dimen/dialog_padding_micro"
+                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            style="?android:attr/buttonBarButtonStyle"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content" />
+                    <Button android:id="@+id/button2"
+                            android:layout_gravity="start"
+                            android:layout_weight="1"
+                            android:layout_marginLeft="@dimen/dialog_padding_micro"
+                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            style="?android:attr/buttonBarButtonStyle"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content" />
+                </LinearLayout>
+            </FrameLayout>
         </LinearLayout>
-     </LinearLayout>
-</LinearLayout>
+    </ScrollView>
+</FrameLayout>
diff --git a/core/res/res/layout/preference_list_fragment.xml b/core/res/res/layout/preference_list_fragment.xml
index fc53a1a..c43975e 100644
--- a/core/res/res/layout/preference_list_fragment.xml
+++ b/core/res/res/layout/preference_list_fragment.xml
@@ -33,8 +33,6 @@
             style="?attr/preferenceFragmentListStyle"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:paddingTop="0dip"
-            android:paddingBottom="@dimen/preference_fragment_padding_bottom"
             android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
             android:clipToPadding="false"
             android:drawSelectorOnTop="false"
diff --git a/core/res/res/layout/preference_list_fragment_material.xml b/core/res/res/layout/preference_list_fragment_material.xml
index e411c0e..db2fe7d 100644
--- a/core/res/res/layout/preference_list_fragment_material.xml
+++ b/core/res/res/layout/preference_list_fragment_material.xml
@@ -32,8 +32,6 @@
         <ListView android:id="@android:id/list"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
-            android:paddingTop="0dip"
-            android:paddingBottom="@dimen/preference_fragment_padding_bottom"
             style="?attr/preferenceFragmentListStyle"
             android:scrollbarStyle="@integer/preference_fragment_scrollbarStyle"
             android:clipToPadding="false"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c03fb5b..a4a7e4e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Ontspeld"</string>
     <string name="app_info" msgid="6856026610594615344">"Programinligting"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Herbegin sessie"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tik om \'n nuwe demonstrasiesessie te begin"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Begin tans demonstrasie"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Herbegin tans sessie"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Doen \'n fabriekterugstelling om hierdie toestel sonder beperkinge te gebruik"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Raak om meer te wete te kom."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 55f0f2a..fce15e6 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"አሁን"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ደ  ውስጥ </item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ደ  ውስጥ </item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ደ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ደ</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ሰ  ውስጥ </item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g>  ሰ  ውስጥ </item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ሰ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ሰ</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g>  ቀ ውስጥ </item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ቀ ውስጥ </item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ቀ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ቀ</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ  ውስጥ </item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ  ውስጥ </item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ዓ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ዓ</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ደቂቃ ውስጥ</item>
-      <item quantity="other"> በ <xliff:g id="COUNT_1">%d</xliff:g> ደቂቃዎች ውስጥ</item>
+      <item quantity="one">በ<xliff:g id="COUNT_1">%d</xliff:g> ደ ውስጥ</item>
+      <item quantity="other">በ<xliff:g id="COUNT_1">%d</xliff:g> ደ ውስጥ</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ሰ ውስጥ</item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ሰ ውስጥ</item>
+      <item quantity="one">በ<xliff:g id="COUNT_1">%d</xliff:g> ሰ ውስጥ</item>
+      <item quantity="other">በ<xliff:g id="COUNT_1">%d</xliff:g> ሰ ውስጥ</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ቀ ውስጥ</item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ቀ ውስጥ</item>
+      <item quantity="one">በ<xliff:g id="COUNT_1">%d</xliff:g> ቀ ውስጥ</item>
+      <item quantity="other">በ<xliff:g id="COUNT_1">%d</xliff:g> ቀ ውስጥ</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one"> በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ ውስጥ</item>
-      <item quantity="other"> በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ ውስጥ</item>
+      <item quantity="one">በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ ውስጥ</item>
+      <item quantity="other">በ<xliff:g id="COUNT_1">%d</xliff:g> ዓ ውስጥ</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one">ከ<xliff:g id="COUNT_1">%d</xliff:g> ደቂቃዎች በፊት</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ንቀል"</string>
     <string name="app_info" msgid="6856026610594615344">"የመተግበሪያ መረጃ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"ክፍለ-ጊዜን ዳግም ያስጀምሩ"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"አዲስ የማሳያ ክፍለ-ጊዜን ለመጀመር መታ ያድርጉ"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ማሳያን ዳግም በማስጀመር ላይ"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"ክፍለ-ጊዜን ዳግም በማስጀመር ላይ"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ይህን መሣሪያ ያለምንም ገደብ ለመጠቀም የፋብሪካ ዳግም ያስጀምሩ"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"የበለጠ ለመረዳት ይንኩ።"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ተሰናክሏል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index bd6de2e..f7213fc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -888,12 +888,12 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"الآن"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g>دقيقة</item>
+      <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
       <item quantity="two"><xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> دقائق</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g>دقيقة</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>دقيقة</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> دقيقة</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
       <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
@@ -904,52 +904,52 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ساعة</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g>يوم</item>
+      <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g> يوم</item>
       <item quantity="two">يومان <xliff:g id="COUNT_1">%d</xliff:g></item>
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> أيام</item>
       <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> يومًا</item>
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> يوم</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>يوم</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> يوم</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
       <item quantity="zero"><xliff:g id="COUNT_1">%d</xliff:g> عام</item>
       <item quantity="two">عامان <xliff:g id="COUNT_1">%d</xliff:g></item>
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> أعوام</item>
       <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> عامًا</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>عام</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>عام</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> عام</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> عام</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="zero">في<xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
+      <item quantity="zero">في <xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
       <item quantity="two">في دقيقتين (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
-      <item quantity="few">في<xliff:g id="COUNT_1">%d</xliff:g> دقائق</item>
+      <item quantity="few">في <xliff:g id="COUNT_1">%d</xliff:g> دقائق</item>
       <item quantity="many">في <xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
-      <item quantity="other">في<xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
-      <item quantity="one">في<xliff:g id="COUNT_0">%d</xliff:g> دقيقة</item>
+      <item quantity="other">في <xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
+      <item quantity="one">في <xliff:g id="COUNT_0">%d</xliff:g> دقيقة</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="zero">في<xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
+      <item quantity="zero">في <xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
       <item quantity="two">في ساعتين (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
       <item quantity="few">في <xliff:g id="COUNT_1">%d</xliff:g> ساعات</item>
       <item quantity="many">في <xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
-      <item quantity="other">في<xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
-      <item quantity="one">في<xliff:g id="COUNT_0">%d</xliff:g>ساعة</item>
+      <item quantity="other">في <xliff:g id="COUNT_1">%d</xliff:g> ساعة</item>
+      <item quantity="one">في <xliff:g id="COUNT_0">%d</xliff:g> ساعة</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="zero">في<xliff:g id="COUNT_1">%d</xliff:g>يوم</item>
+      <item quantity="zero">في <xliff:g id="COUNT_1">%d</xliff:g> يوم</item>
       <item quantity="two">في يومين (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
-      <item quantity="few">في<xliff:g id="COUNT_1">%d</xliff:g> أيام</item>
-      <item quantity="many">في<xliff:g id="COUNT_1">%d</xliff:g> يومًا</item>
-      <item quantity="other">في<xliff:g id="COUNT_1">%d</xliff:g>يوم</item>
-      <item quantity="one">في<xliff:g id="COUNT_0">%d</xliff:g> يوم</item>
+      <item quantity="few">في <xliff:g id="COUNT_1">%d</xliff:g> أيام</item>
+      <item quantity="many">في <xliff:g id="COUNT_1">%d</xliff:g> يومًا</item>
+      <item quantity="other">في <xliff:g id="COUNT_1">%d</xliff:g> يوم</item>
+      <item quantity="one">في <xliff:g id="COUNT_0">%d</xliff:g> يوم</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="zero">في<xliff:g id="COUNT_1">%d</xliff:g> عام</item>
+      <item quantity="zero">في <xliff:g id="COUNT_1">%d</xliff:g> عام</item>
       <item quantity="two">في عامين (<xliff:g id="COUNT_1">%d</xliff:g>)</item>
-      <item quantity="few">في<xliff:g id="COUNT_1">%d</xliff:g> أعوام</item>
-      <item quantity="many">في<xliff:g id="COUNT_1">%d</xliff:g> عامًا</item>
-      <item quantity="other">في<xliff:g id="COUNT_1">%d</xliff:g>عام</item>
-      <item quantity="one">في<xliff:g id="COUNT_0">%d</xliff:g> عام</item>
+      <item quantity="few">في <xliff:g id="COUNT_1">%d</xliff:g> أعوام</item>
+      <item quantity="many">في <xliff:g id="COUNT_1">%d</xliff:g> عامًا</item>
+      <item quantity="other">في <xliff:g id="COUNT_1">%d</xliff:g> عام</item>
+      <item quantity="one">في <xliff:g id="COUNT_0">%d</xliff:g> عام</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="zero">قبل <xliff:g id="COUNT_1">%d</xliff:g> دقيقة</item>
@@ -1793,6 +1793,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"إزالة تثبيت"</string>
     <string name="app_info" msgid="6856026610594615344">"معلومات عن التطبيق"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"إعادة تشغيل الجلسة"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"انقر لبدء جلسة عرض توضيحي جديدة"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"جارٍ بدء العرض التوضيحي"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"جارٍ إعادة تشغيل الجلسة"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"يمكنك إعادة تعيين بيانات المصنع لاستخدام هذا الجهاز بدون قيود"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"المس للتعرف على مزيد من المعلومات."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"تم تعطيل <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index aa84ed0a..e0009d2 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Çıxarın"</string>
     <string name="app_info" msgid="6856026610594615344">"Tətbiq məlumatı"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Sessiyanı Yenidən Başladın"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Yeni demo sessiyanı başlamaq üçün tıklayın"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo başlayır"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sessiya yenidən başlayır"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı məhdudiyyətsiz istifadə etmək üçün zavod sıfırlaması edin"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha çox məlumat üçün toxunun."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 1620f63..fdeb9ed 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -125,15 +125,11 @@
     <string name="roamingTextSearching" msgid="8360141885972279963">"Pretraživanje usluge"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Pozivanje preko Wi-Fi-ja"</string>
   <string-array name="wfcOperatorErrorAlertMessages">
-    <item msgid="2254967670088539682">"Da biste upućivali pozive i slali poruke preko Wi-Fi-ja, prvo zatražite od mobilnog operatera da vam omogući ovu uslugu. Zatim u Podešavanjima ponovo uključite Pozivanje preko Wi-Fi-ja."</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="6177300162212449033">"Registrujte se kod mobilnog operatera"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi pozivanje preko operatera %s"</item>
-  </string-array>
+    <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Prednost ima mobilna mreža"</string>
@@ -169,11 +165,7 @@
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="tv" msgid="516619861191025923">"Memorijski prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Skladište telefona je puno! Izbrišite neke datoteke kako biste oslobodili prostor."</string>
-    <plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
-      <item quantity="one">Instalirani su autoriteti za izdavanje sertifikata</item>
-      <item quantity="few">Instalirani su autoriteti za izdavanje sertifikata</item>
-      <item quantity="other">Instalirani su autoriteti za izdavanje sertifikata</item>
-    </plurals>
+    <!-- no translation found for ssl_ca_cert_warning (5106721205300213569) -->
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Od strane administratora profila za posao"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od strane <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -220,9 +212,9 @@
     <string name="bugreport_title" msgid="2667494803742548533">"Napravi izveštaj o grešci"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupiti informacije o trenutnom stanju uređaja kako bi bile poslate u poruci e-pošte. Od započinjanja izveštaja o grešci do trenutka za njegovo slanje proći će neko vreme; budite strpljivi."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktiv. izveštaj"</string>
-    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Koristite ovo u većini slučajeva. To vam omogućava da pratite napredak izveštaja, da unosite dodatne detalje o problemu i da snimate snimke ekrana. Verovatno će izostaviti neke manje korišćene odeljke za koje pravljenje izveštaja dugo traje."</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Koristite ovo u većini slučajeva. To vam omogućava da pratite napredak izveštaja i da unosite dodatne detalje o problemu. Verovatno će izostaviti neke manje korišćene odeljke za koje pravljenje izveštaja dugo traje."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"Kompletan izveštaj"</string>
-    <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Koristite ovu opciju radi minimalnih sistemskih smetnji kada uređaj ne reaguje, prespor je ili su vam potrebni svi odeljci izveštaja. Ne dozvoljava vam unos dodatnih detalja niti snimanje dodatnih snimaka ekrana."</string>
+    <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Koristite ovu opciju radi minimalnih sistemskih smetnji kada uređaj ne reaguje, prespor je ili su vam potrebni svi odeljci izveštaja. Ne pravi snimak ekrana niti vam dozvoljava unos dodatnih detalja."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
       <item quantity="one">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekundu.</item>
       <item quantity="few">Napravićemo snimak ekrana radi izveštaja o grešci za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
@@ -266,7 +258,7 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Preuzima sadržaj prozora"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Proverava sadržaj prozora sa kojim ostvarujete interakciju."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključi Istraživanja dodirom"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Stavke koje dodirnete će biti izgovorene naglas, a možete da se krećete po ekranu pokretima."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Stavke koje dodirnete će biti izgovorene, a možete da se krećete po ekranu pokretima."</string>
     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Uključi poboljšanu pristupačnost veba"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Mogu da se instaliraju skripte da bi sadržaj aplikacija bio pristupačniji."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Prati tekst koji unosite"</string>
@@ -607,7 +599,7 @@
     <string name="phoneTypeRadio" msgid="4093738079908667513">"Radio"</string>
     <string name="phoneTypeTelex" msgid="3367879952476250512">"Teleks"</string>
     <string name="phoneTypeTtyTdd" msgid="8606514378585000044">"TTY TDD"</string>
-    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Poslovni mobilni"</string>
+    <string name="phoneTypeWorkMobile" msgid="1311426989184065709">"Broj poslovnog mobilnog telefona"</string>
     <string name="phoneTypeWorkPager" msgid="649938731231157056">"Poslovni pejdžer"</string>
     <string name="phoneTypeAssistant" msgid="5596772636128562884">"Pomoćnik"</string>
     <string name="phoneTypeMms" msgid="7254492275502768992">"MMS"</string>
@@ -665,7 +657,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN kôd"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK kôd"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN kôd"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"Dodirnite za unos lozinke"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite da biste uneli lozinku"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Otkucajte lozinku da biste otključali"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN kôd je netačan."</string>
@@ -865,87 +857,6 @@
       <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sata</item>
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sati</item>
     </plurals>
-    <string name="now_string_shortest" msgid="8912796667087856402">"sada"</string>
-    <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-    </plurals>
-    <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> č</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> č</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> č</item>
-    </plurals>
-    <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-    </plurals>
-    <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> god</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> god</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> god</item>
-    </plurals>
-    <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-    </plurals>
-    <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> č</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> č</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> č</item>
-    </plurals>
-    <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-    </plurals>
-    <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> god</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> god</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> god</item>
-    </plurals>
-    <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
-      <item quantity="one">pre <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-      <item quantity="few">pre <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-      <item quantity="other">pre <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-    </plurals>
-    <plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
-      <item quantity="one">pre <xliff:g id="COUNT_1">%d</xliff:g> sata</item>
-      <item quantity="few">pre <xliff:g id="COUNT_1">%d</xliff:g> sata</item>
-      <item quantity="other">pre <xliff:g id="COUNT_1">%d</xliff:g> sati</item>
-    </plurals>
-    <plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
-      <item quantity="one">Pre <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-      <item quantity="few">Pre <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-      <item quantity="other">Pre <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-    </plurals>
-    <plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
-      <item quantity="one">pre <xliff:g id="COUNT_1">%d</xliff:g> godine</item>
-      <item quantity="few">pre <xliff:g id="COUNT_1">%d</xliff:g> godine</item>
-      <item quantity="other">pre <xliff:g id="COUNT_1">%d</xliff:g> godina</item>
-    </plurals>
-    <plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> minut</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-    </plurals>
-    <plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> sat</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> sata</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> sati</item>
-    </plurals>
-    <plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-    </plurals>
-    <plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> godinu</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> godine</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> godina</item>
-    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problem sa video snimkom"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Ovaj video ne može da se strimuje na ovom uređaju."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Ne možete da pustite ovaj video."</string>
@@ -977,7 +888,7 @@
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
-    <string name="app_running_notification_text" msgid="1197581823314971177">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
+    <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
     <string name="ok" msgid="5970060430562524910">"Potvrdi"</string>
     <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
     <string name="yes" msgid="5362982303337969312">"Potvrdi"</string>
@@ -1017,7 +928,8 @@
     <string name="aerr_process" msgid="6201597323218674729">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen"</string>
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> se stalno zaustavlja"</string>
-    <string name="aerr_restart" msgid="7581308074153624475">"Ponovo otvori aplikaciju"</string>
+    <string name="aerr_restart" msgid="9001379185665886595">"Ponovo pokreni aplikaciju"</string>
+    <string name="aerr_reset" msgid="7645427603514220451">"Resetuj i ponovo pokreni aplikaciju"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošaljite povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Ignoriši dok se uređaj ne pokrene ponovo"</string>
@@ -1043,14 +955,12 @@
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android se nadograđuje…"</string>
     <string name="android_start_title" msgid="8418054686415318207">"Android se pokreće…"</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Memorija se optimizuje."</string>
-    <string name="android_upgrading_notification_title" msgid="1619393112444671028">"Android se nadograđuje…"</string>
-    <string name="android_upgrading_notification_body" msgid="5761201379457064286">"Neke aplikacije možda neće ispravno funkcionisati dok se nadogradnja ne dovrši"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimizovanje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="android_preparing_apk" msgid="8162599310274079154">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Završavanje pokretanja."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Aplikacija <xliff:g id="APP">%1$s</xliff:g> je pokrenuta"</string>
-    <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dodirnite da biste prešli na aplikaciju"</string>
+    <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Dodirnite da biste prešli na aplikaciju"</string>
     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite li da pređete na drugu aplikaciju?"</string>
     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta druga aplikacija koja mora da bude zaustavljena da biste mogli da pokrenete novu."</string>
     <string name="old_app_action" msgid="493129172238566282">"Vrati se u <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -1058,7 +968,7 @@
     <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zaustavlja staru aplikaciju bez čuvanja."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
-    <string name="dump_heap_notification_detail" msgid="6901391084243999274">"Snimak dinamičkog dela memorije je napravljen; dodirnite za deljenje"</string>
+    <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Snimak dinamičkog dela memorije je napravljen; dodirnite za deljenje"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Želite li da delite snimak dinamičkog dela memorije?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"Proces <xliff:g id="PROC">%1$s</xliff:g> je premašio ograničenje memorije za proces od <xliff:g id="SIZE">%2$s</xliff:g>. Snimak dinamičkog dela memorije je dostupan i možete da ga delite sa programerom. Budite oprezni: ovaj snimak dinamičkog dela memorije može da sadrži neke lične podatke kojima aplikacija može da pristupa."</string>
     <string name="sendText" msgid="5209874571959469142">"Izaberite radnju za tekst"</string>
@@ -1096,7 +1006,7 @@
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup internetu"</string>
-    <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Dodirnite za opcije"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nije moguće povezati sa Wi-Fi mrežom"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li da dozvolite povezivanje?"</string>
@@ -1106,7 +1016,7 @@
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokrenite Wi-Fi Direct. Time ćete isključiti klijenta/hotspot za Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nije moguće pokrenuti Wi-Fi Direct."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je uključen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dodirnite za podešavanja"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za podešavanja"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
     <string name="decline" msgid="2112225451706137894">"Odbij"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslata"</string>
@@ -1158,9 +1068,9 @@
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Povezano sa USB dodatkom"</string>
-    <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za još opcija."</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za još opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
-    <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Izveštaj o grešci se generiše…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Želite li da podelite izveštaj o grešci?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Deli se izveštaj o grešci…"</string>
@@ -1180,9 +1090,9 @@
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
     <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Za prenos slika i medija"</string>
     <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen"</string>
-    <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da biste ga popravili."</string>
+    <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da biste ga popravili."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"Uređaj <xliff:g id="NAME">%s</xliff:g> nije podržan"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Ovaj uređaj ne podržava ovaj uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da biste podesili podržani format."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Ovaj uređaj ne podržava uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da biste podesili podržani format."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Uređaj <xliff:g id="NAME">%s</xliff:g> je neočekivano uklonjen"</string>
     <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Isključite uređaj <xliff:g id="NAME">%s</xliff:g> pre uklanjanja da ne biste izgubili podatke"</string>
     <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen"</string>
@@ -1218,7 +1128,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instaliranja. To joj dozvoljava da vidi detalje o aktivnim instalacijama paketa."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtevanje paketa za instaliranje"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava da aplikacija zahteva instalaciju paketa."</string>
-    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Dodirnite dvaput za kontrolu zumiranja"</string>
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput da biste kontrolisali zum"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Nije moguće dodati vidžet."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Idi"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Pretraži"</string>
@@ -1249,20 +1159,20 @@
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usluga rangiranja obaveštenja"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN je aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
-    <string name="vpn_text" msgid="1610714069627824309">"Dodirnite da biste upravljali mrežom."</string>
-    <string name="vpn_text_long" msgid="4907843483284977618">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
+    <string name="vpn_text" msgid="3011306607126450322">"Dodirnite da biste upravljali mrežom."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Povezano sa sesijom <xliff:g id="SESSION">%s</xliff:g>. Dodirnite da biste upravljali mrežom."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje stalno uključenog VPN-a..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Stalno uključeni VPN je povezan"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška stalno uključenog VPN-a"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite da biste konfigurisali"</string>
+    <string name="vpn_lockdown_config" msgid="6415899150671537970">"Dodirnite da biste konfigurisali"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
     <string name="submit" msgid="1602335572089911941">"Pošalji"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Režim rada u automobilu je omogućen"</string>
-    <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Dodirnite da biste izašli iz režima rada u automobilu."</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Dodirnite da biste izašli iz režima rada u automobilu."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Aktivno povezivanje sa internetom preko mobilnog uređaja ili hotspot"</string>
-    <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite da biste podesili."</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"Dodirnite da biste podesili."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Nazad"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Next"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
@@ -1296,7 +1206,7 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj nalog"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećavanje"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"Smanjivanje"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> dodirnite i zadržite."</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"<xliff:g id="VALUE">%s</xliff:g> dodirnite i zadržite."</string>
     <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Prevucite nagore da biste povećali, a nadole da biste smanjili."</string>
     <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Povećavanje minuta"</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Smanjivanje minuta"</string>
@@ -1340,7 +1250,7 @@
     <string name="storage_usb" msgid="3017954059538517278">"USB memorija"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Izmeni"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje o potrošnji podataka"</string>
-    <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za potrošnju i podešavanja."</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"Dodirnite za pregled kor. i pod."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Nema više 2G-3G podataka"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Nema više 4G podataka"</string>
     <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Nema više podataka za mobilne"</string>
@@ -1352,7 +1262,7 @@
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Prekoračenje prenosa Wi-Fi podat."</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> preko navedenog ograničenja."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Pozadinski podaci su ograničeni"</string>
-    <string name="data_usage_restricted_body" msgid="469866376337242726">"Dodirnite za uklanjanje ograničenja."</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Dodirnite da biste uklonili ograničenje."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Bezbednosni sertifikat"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Ovaj sertifikat je važeći."</string>
     <string name="issued_to" msgid="454239480274921032">"Izdato za:"</string>
@@ -1569,7 +1479,8 @@
     <string name="select_year" msgid="7952052866994196170">"Izaberite godinu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Izbrisali ste <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> na poslu"</string>
-    <string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i zadržite Nazad."</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"Da biste otkačili ovaj ekran, istovremeno dodirnite i zadržite Nazad i Pregled."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da biste otkačili ovaj ekran, dodirnite i zadržite Pregled."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je zakačena: otkačinjanje nije dozvoljeno na ovom uređaju."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran je otkačen"</string>
@@ -1580,9 +1491,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao je administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao je vaš admiistrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi produžila vreme trajanja baterije, ušteda baterije smanjuje performanse uređaja i ograničava vibraciju, usluge lokacije i većinu pozadinskih podataka. Imejl, razmena poruka i druge aplikacije koje se oslanjaju na sinhronizaciju možda neće da se ažuriraju ako ih ne otvorite.\n\nUšteda baterije se automatski isključuje kada se uređaj puni."</string>
-    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjila potrošnja podataka, Ušteda podataka sprečava neke aplikacije da šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može da pristupa podacima, ali će to činiti ređe. Na primer, slike se neće prikazivati dok ih ne dodirnete."</string>
-    <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
-    <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
+    <!-- no translation found for data_saver_description (6015391409098303235) -->
+    <skip />
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d minut (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1644,8 +1554,6 @@
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtev je promenjen u USSD zahtev."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtev je promenjen u novi SS zahtev."</string>
     <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za Work"</string>
-    <string name="expand_button_content_description" msgid="5855955413376384681">"Dugme Proširi"</string>
-    <string name="expand_action_accessibility" msgid="5307730695723718254">"uključite/isključite proširenje"</string>
     <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB port za periferijske uređaje"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB port za periferijske uređaje"</string>
@@ -1653,7 +1561,6 @@
     <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Zatvori preklopni meni"</string>
     <string name="maximize_button_text" msgid="7543285286182446254">"Uvećaj"</string>
     <string name="close_button_text" msgid="3937902162644062866">"Zatvori"</string>
-    <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
     <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
       <item quantity="one">Izabrana je <xliff:g id="COUNT_1">%1$d</xliff:g> stavka</item>
       <item quantity="few">Izabrane su <xliff:g id="COUNT_1">%1$d</xliff:g> stavke</item>
@@ -1687,5 +1594,4 @@
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Resetujte uređaj na fabrička podešavanja da biste ga koristili bez ograničenja"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
-    <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
 </resources>
diff --git a/core/res/res/values-be-rBY/strings.xml b/core/res/res/values-be-rBY/strings.xml
index 6cdef81..2e82a72 100644
--- a/core/res/res/values-be-rBY/strings.xml
+++ b/core/res/res/values-be-rBY/strings.xml
@@ -23,7 +23,7 @@
     <string name="byteShort" msgid="8340973892742019101">"B"</string>
     <string name="kilobyteShort" msgid="5973789783504771878">"Кб"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"Мб"</string>
-    <string name="gigabyteShort" msgid="3259882455212193214">"ГБ"</string>
+    <string name="gigabyteShort" msgid="3259882455212193214">"Гб"</string>
     <string name="terabyteShort" msgid="231613018159186962">"Тб"</string>
     <string name="petabyteShort" msgid="5637816680144990219">"Пб"</string>
     <string name="fileSizeSuffix" msgid="8897567456150907538">"<xliff:g id="NUMBER">%1$s</xliff:g> <xliff:g id="UNIT">%2$s</xliff:g>"</string>
@@ -126,15 +126,11 @@
     <string name="roamingTextSearching" msgid="8360141885972279963">"Пошук службы"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi-тэлефанія"</string>
   <string-array name="wfcOperatorErrorAlertMessages">
-    <item msgid="2254967670088539682">"Каб рабіць выклікі і адпраўляць паведамленні па Wi-Fi, спачатку папрасіце свайго аператара наладзіць гэту паслугу. Затым зноў уключыце Wi-Fi-тэлефанію ў меню Налады."</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="6177300162212449033">"Зарэгіструйцеся ў свайго аператара"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi-тэлефанія %s"</item>
-  </string-array>
+    <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Выкл."</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Прыярытэт Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Прыярытэт мабільнай сеткі"</string>
@@ -170,12 +166,7 @@
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Сховішча гадзінніка перапоўнена. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
     <string name="low_memory" product="tv" msgid="516619861191025923">"Сховішча тэлевізара перапоўнена. Выдаліце некаторыя файлы, каб вызваліць месца."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Памяць тэлефона поўная. Выдаліце ​​некаторыя файлы, каб вызваліць месца."</string>
-    <plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
-      <item quantity="one">Усталяваны цэнтры сертыфікацыі</item>
-      <item quantity="few">Усталяваны цэнтры сертыфікацыі</item>
-      <item quantity="many">Усталяваны цэнтры сертыфікацыі</item>
-      <item quantity="other">Усталяваны цэнтры сертыфікацыі</item>
-    </plurals>
+    <!-- no translation found for ssl_ca_cert_warning (5106721205300213569) -->
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Невядомая трэцяя асоба"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"Адміністратар вашага працоўнага профілю"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"<xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -211,7 +202,7 @@
     <string name="shutdown_confirm_question" msgid="2906544768881136183">"Закрыць?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"Перазагрузка ў бяспечным рэжыме"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"Хочаце перазагрузіцца ў бяспечным рэжыме? Гэта дазволіць адключыць усе іншыя ўсталяваныя прыкладанні. Пасля перазагрузкi iх праца будзе адноўлена."</string>
-    <string name="recent_tasks_title" msgid="3691764623638127888">"Нядаўнія"</string>
+    <string name="recent_tasks_title" msgid="3691764623638127888">"Апошнія"</string>
     <string name="no_recent_tasks" msgid="8794906658732193473">"Няма апошніх прыкладанняў."</string>
     <string name="global_actions" product="tablet" msgid="408477140088053665">"Параметры планшэта"</string>
     <string name="global_actions" product="tv" msgid="7240386462508182976">"Параметры ТБ"</string>
@@ -222,9 +213,9 @@
     <string name="bugreport_title" msgid="2667494803742548533">"Справаздача пра памылку"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Будзе збiрацца iнфармацыя пра бягучы стан прылады, якая будзе адпраўляцца на электронную пошту. Стварэнне справаздачы пра памылкi зойме некаторы час."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Інтэрактыўная справаздача"</string>
-    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Выкарыстоўвайце ў большасці выпадкаў. Гэта дазваляе сачыць за ходам справаздачы, уводзіць дадатковыя звесткі аб праблеме і рабіць здымкі экрана. Могуць быць прапушчаны некаторыя раздзелы, якія выкарыстоўваюцца менш і паведамленне пра якія займае шмат часу."</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Выкарыстоўвайце ў большасці выпадкаў. Гэта дазваляе сачыць за ходам справаздачы і ўводзіць дадатковыя звесткі аб праблеме. Могуць быць прапушчаны некаторыя раздзелы, якія выкарыстоўваюцца менш і паведаміць пра якія зойме шмат часу."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"Поўная справаздача"</string>
-    <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Выкарыстоўвайце гэту опцыю, каб забяспечыць мінімальнае ўмяшанне сістэмы, калі прылада не адказвае ці працуе занадта павольна, або калі вам патрэбны ўсе раздзелы справаздачы. Выкарыстоўваючы гэту опцыю, вы не зможаце ўвесці больш падрабязную інфармацыю або зрабіць дадатковыя здымкі экрана."</string>
+    <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Выкарыстоўвайце гэту опцыю, каб забяспечыць мінімальнае ўмяшанне сістэмы, калі прылада не адказвае ці працуе занадта павольна або калі вам патрэбны ўсе раздзелы справаздачы. Выкарыстоўваючы гэту опцыю, вы не зможаце зрабіць здымак экрана або ўвесці больш падрабязную інфармацыю."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
       <item quantity="one">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунду.</item>
       <item quantity="few">Здымак экрана для справаздачы пра памылкі будзе зроблены праз <xliff:g id="NUMBER_1">%d</xliff:g> секунды.</item>
@@ -269,7 +260,7 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Атрымайце змесцiва акна"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Вывучыце змесцiва акна, з якiм вы працуеце."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Уключыце Explore by Touch"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Элементы, да якіх дакрануліся, будуць агучаны, а экранам можна даследаваць пры дапамозе жэстаў."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Элемент, да якiх дакраналiся, могуць быць агучаны, а экран будзе працаваць з жэстамi."</string>
     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Уключыце паляпшэнне вэб-даступнасці"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Сцэнарыi могуць быць усталяваны, каб зрабіць змесцiва прыкладання больш даступным."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Глядзiце, што набiраеце"</string>
@@ -530,12 +521,12 @@
     <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"Сачыць за колькасцю няправільна набраных пароляў падчас разблакіроўкі экрана і блакіраваць тэлефон або сцерці ўсе даныя гэтага карыстальніка, калі няправільны пароль набраны занадта шмат разоў."</string>
     <string name="policylab_resetPassword" msgid="4934707632423915395">"Змяніць блакіроўку экрана"</string>
     <string name="policydesc_resetPassword" msgid="1278323891710619128">"Змяніць блакіроўку экрана."</string>
-    <string name="policylab_forceLock" msgid="2274085384704248431">"Заблакіраваць экран"</string>
-    <string name="policydesc_forceLock" msgid="1141797588403827138">"Кіраваць як і калі блакіруецца экран."</string>
-    <string name="policylab_wipeData" msgid="3910545446758639713">"Сцерці ўсе даныя"</string>
-    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Cцерці даныя з планшэта без папярэджання, выканаўшы скід да заводскіх даных."</string>
+    <string name="policylab_forceLock" msgid="2274085384704248431">"Заблакаваць экран"</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Кіраванне часам і спосабам блакавання экрана"</string>
+    <string name="policylab_wipeData" msgid="3910545446758639713">"Сцерці ўсе дадзеныя"</string>
+    <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Выдаліць дадзеныя з планшэта без папярэджання, выканаўшы скід налад."</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Сцерці даныя з тэлевізара без папярэджання, выканаўшы скід да заводскіх налад."</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Сцерці даныя з тэлефона без папярэджання, выканаўшы скід да заводскіх налад."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Выдаліць дадзеныя з тэлефона без папярэджання, выканаўшы скід налад."</string>
     <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Сцерці карыстальніцкія даныя"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Сцерці даныя гэтага карыстальніка на дадзеным планшэце без папярэджання."</string>
     <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Сцерці даныя гэтага карыстальніка на дадзеным тэлевізары без папярэджання."</string>
@@ -551,7 +542,7 @@
     <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Адкл.некат.функцыі блак.экрана"</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Забараніць выкарыстанне некаторых функцый блакіроўкі экрана."</string>
   <string-array name="phoneTypes">
-    <item msgid="8901098336658710359">"Хатні"</item>
+    <item msgid="8901098336658710359">"Галоўная старонка"</item>
     <item msgid="869923650527136615">"Мабільны"</item>
     <item msgid="7897544654242874543">"Працоўны"</item>
     <item msgid="1103601433382158155">"Працоўны факс"</item>
@@ -594,7 +585,7 @@
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Карыстальніцкі"</string>
-    <string name="phoneTypeHome" msgid="2570923463033985887">"Хатні"</string>
+    <string name="phoneTypeHome" msgid="2570923463033985887">"Галоўная старонка"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Мабільны"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"Працоўны"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Працоўны факс"</string>
@@ -602,7 +593,7 @@
     <string name="phoneTypePager" msgid="7582359955394921732">"Пэйджар"</string>
     <string name="phoneTypeOther" msgid="1544425847868765990">"Іншы"</string>
     <string name="phoneTypeCallback" msgid="2712175203065678206">"Зваротны выклік"</string>
-    <string name="phoneTypeCar" msgid="8738360689616716982">"Тэл. у машыне"</string>
+    <string name="phoneTypeCar" msgid="8738360689616716982">"Машына"</string>
     <string name="phoneTypeCompanyMain" msgid="540434356461478916">"Асноўны тэлефон кампаніі"</string>
     <string name="phoneTypeIsdn" msgid="8022453193171370337">"ISDN"</string>
     <string name="phoneTypeMain" msgid="6766137010628326916">"Галоўны"</string>
@@ -619,16 +610,16 @@
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Гадавіна"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Іншае"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Карыстальніцкі"</string>
-    <string name="emailTypeHome" msgid="449227236140433919">"Хатні"</string>
+    <string name="emailTypeHome" msgid="449227236140433919">"Галоўная старонка"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Працоўны"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Іншы"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Мабільны"</string>
     <string name="postalTypeCustom" msgid="8903206903060479902">"Карыстальніцкі"</string>
-    <string name="postalTypeHome" msgid="8165756977184483097">"Хатні"</string>
+    <string name="postalTypeHome" msgid="8165756977184483097">"Галоўная старонка"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Працоўны"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Іншы"</string>
     <string name="imTypeCustom" msgid="2074028755527826046">"Карыстальніцкі"</string>
-    <string name="imTypeHome" msgid="6241181032954263892">"Хатні"</string>
+    <string name="imTypeHome" msgid="6241181032954263892">"Галоўная старонка"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Працоўны"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Іншы"</string>
     <string name="imProtocolCustom" msgid="6919453836618749992">"Карыстальніцкі"</string>
@@ -660,7 +651,7 @@
     <string name="relationTypeSister" msgid="1735983554479076481">"Сястра"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Муж/жонка"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Карыстальніцкі"</string>
-    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Хатні"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Галоўная старонка"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Працоўны"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Іншае"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Адсутнічае праграма для прагляду гэтага кантакту."</string>
@@ -668,7 +659,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Увядзіце PUK-код і новы PIN-код"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Новы PIN-код"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Дакраніцеся, каб увесці пароль"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Увядзіце пароль для разблакавання"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Каб разблакаваць, увядзіце PIN-код"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Няправільны PIN-код."</string>
@@ -679,7 +670,7 @@
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Націсніце \"Меню\", каб разблакаваць, або зрабіце экстраны выклік."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Націсніце \"Меню\", каб разблакаваць."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Намалюйце камбінацыю разблакоўкі, каб разблакаваць"</string>
-    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"SOS-выклік"</string>
+    <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Экстранная сітуацыя"</string>
     <string name="lockscreen_return_to_call" msgid="5244259785500040021">"Вярнуцца да выкліку"</string>
     <string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правільна!"</string>
     <string name="lockscreen_pattern_wrong" msgid="4317955014948108794">"Паспрабуйце яшчэ раз"</string>
@@ -846,7 +837,7 @@
     <string name="days" msgid="4774547661021344602">"д."</string>
     <string name="hour" msgid="2126771916426189481">"гадзіна"</string>
     <string name="hours" msgid="894424005266852993">"г."</string>
-    <string name="minute" msgid="9148878657703769868">"хв"</string>
+    <string name="minute" msgid="9148878657703769868">"хв."</string>
     <string name="minutes" msgid="5646001005827034509">"хв."</string>
     <string name="second" msgid="3184235808021478">"с."</string>
     <string name="seconds" msgid="3161515347216589235">"с."</string>
@@ -872,103 +863,6 @@
       <item quantity="many"><xliff:g id="COUNT">%d</xliff:g> гадзін</item>
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> гадзіны</item>
     </plurals>
-    <string name="now_string_shortest" msgid="8912796667087856402">"зараз"</string>
-    <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-    </plurals>
-    <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-    </plurals>
-    <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> дз.</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> дні</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> дз.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> дня</item>
-    </plurals>
-    <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-    </plurals>
-    <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> хв</item>
-    </plurals>
-    <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> гадз</item>
-    </plurals>
-    <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> дз.</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> дні</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> дз.</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> дня</item>
-    </plurals>
-    <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> г.</item>
-    </plurals>
-    <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> хвіліну таму</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> хвіліны таму</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> хвілін таму</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> хвіліны таму</item>
-    </plurals>
-    <plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> гадзіну таму</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> гадзіны таму</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> гадзін таму</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> гадзіны таму</item>
-    </plurals>
-    <plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> дзень таму</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> дні таму</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> дзён таму</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> дня таму</item>
-    </plurals>
-    <plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> год таму</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> гады таму</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> гадоў таму</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> года таму</item>
-    </plurals>
-    <plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> хвіліну</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> хвіліны</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> хвілін</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> хвіліны</item>
-    </plurals>
-    <plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> гадзіну</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> гадзіны</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> гадзін</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> гадзіны</item>
-    </plurals>
-    <plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> дзень</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> дні</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> дзён</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> дня</item>
-    </plurals>
-    <plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
-      <item quantity="one">праз <xliff:g id="COUNT_1">%d</xliff:g> год</item>
-      <item quantity="few">праз <xliff:g id="COUNT_1">%d</xliff:g> гады</item>
-      <item quantity="many">праз <xliff:g id="COUNT_1">%d</xliff:g> гадоў</item>
-      <item quantity="other">праз <xliff:g id="COUNT_1">%d</xliff:g> года</item>
-    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Праблема з відэа"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Відэа не падыходзіць для патокавай перадачы на ​​гэту прыладу."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Немагчыма прайграць гэта відэа."</string>
@@ -1000,15 +894,15 @@
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Некаторыя сістэмныя функцыі могуць не працаваць"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Не хапае сховішча для сістэмы. Пераканайцеся, што ў вас ёсць 250 МБ свабоднага месца, і перазапусціце."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Прыкладанне <xliff:g id="APP_NAME">%1$s</xliff:g> працуе"</string>
-    <string name="app_running_notification_text" msgid="1197581823314971177">"Дакраніцеся, каб атрымаць дадатковую інфармацыю або спыніць праграму."</string>
+    <string name="app_running_notification_text" msgid="4653586947747330058">"Націсніце, каб атрымаць дадатковую інфармацыю або спыніць праграму."</string>
     <string name="ok" msgid="5970060430562524910">"ОК"</string>
-    <string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
+    <string name="cancel" msgid="6442560571259935130">"Адмяніць"</string>
     <string name="yes" msgid="5362982303337969312">"ОК"</string>
-    <string name="no" msgid="5141531044935541497">"Скасаваць"</string>
+    <string name="no" msgid="5141531044935541497">"Адмяніць"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Увага"</string>
     <string name="loading" msgid="7933681260296021180">"Загрузка..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Уключыць"</string>
-    <string name="capital_off" msgid="6815870386972805832">"Выключана"</string>
+    <string name="capital_off" msgid="6815870386972805832">"Адключана"</string>
     <string name="whichApplication" msgid="4533185947064773386">"Завяршыць дзеянне з дапамогай"</string>
     <string name="whichApplicationNamed" msgid="8260158865936942783">"Завяршыць дзеянне з дапамогай %1$s"</string>
     <string name="whichApplicationLabel" msgid="7425855495383818784">"Завяршыць дзеянне"</string>
@@ -1026,10 +920,10 @@
     <string name="whichSendToApplicationLabel" msgid="8878962419005813500">"Адправiць"</string>
     <string name="whichHomeApplication" msgid="4307587691506919691">"Выберыце праграму Галоўнай старонкі"</string>
     <string name="whichHomeApplicationNamed" msgid="4493438593214760979">"Выкарыстоўваць %1$s у якасці праграмы Галоўнай старонкі"</string>
-    <string name="whichHomeApplicationLabel" msgid="809529747002918649">"Зрабіць здымак"</string>
-    <string name="whichImageCaptureApplication" msgid="3680261417470652882">"Зрабіць здымак з дапамогай"</string>
-    <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"Зрабіць здымак з дапамогай %1$s"</string>
-    <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Зрабіць здымак"</string>
+    <string name="whichHomeApplicationLabel" msgid="809529747002918649">"Зняць выяву"</string>
+    <string name="whichImageCaptureApplication" msgid="3680261417470652882">"Здымаць выявы з дапамогай"</string>
+    <string name="whichImageCaptureApplicationNamed" msgid="8619384150737825003">"Здымаць выявы з дапамогай %1$s"</string>
+    <string name="whichImageCaptureApplicationLabel" msgid="6390303445371527066">"Зняць выяву"</string>
     <string name="alwaysUse" msgid="4583018368000610438">"Выкарыстоўваць па змаўчанні для гэтага дзеяння."</string>
     <string name="use_a_different_app" msgid="8134926230585710243">"Выкарыстоўваць іншую праграму"</string>
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"Ачысціць па змаўчанні ў раздзеле \"Налады сістэмы &gt; Прыкладанні &gt; Спампаваныя\"."</string>
@@ -1040,7 +934,8 @@
     <string name="aerr_process" msgid="6201597323218674729">"Працэс <xliff:g id="PROCESS">%1$s</xliff:g> спыніўся"</string>
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> шматразова спыняе працу"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> шматразова спыняе працу"</string>
-    <string name="aerr_restart" msgid="7581308074153624475">"Адкрыць праграму зноў"</string>
+    <string name="aerr_restart" msgid="9001379185665886595">"Перазапусціць праграму"</string>
+    <string name="aerr_reset" msgid="7645427603514220451">"Скінуць і перазапусціць праграму"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Адправіць водгук"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Закрыць"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Адключыць гук да перазагрузкі прылады"</string>
@@ -1066,14 +961,12 @@
     <string name="android_upgrading_title" msgid="1584192285441405746">"Абнаўленне Android..."</string>
     <string name="android_start_title" msgid="8418054686415318207">"Android запускаецца..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Аптымізацыя сховішча."</string>
-    <string name="android_upgrading_notification_title" msgid="1619393112444671028">"Абнаўленне Android"</string>
-    <string name="android_upgrading_notification_body" msgid="5761201379457064286">"Пэўныя праграмы могуць не працаваць належным чынам, пакуль не скончыцца абнаўленне"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Аптымізацыя прыкладання <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="android_preparing_apk" msgid="8162599310274079154">"Падрыхтоўка <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Запуск прыкладанняў."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Завяршэнне загрузкі."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Прыкладанне \"<xliff:g id="APP">%1$s</xliff:g>\" запушчанае"</string>
-    <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Дакраніцеся, каб пераключыцца на праграму"</string>
+    <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Націсніце, каб перайсці да прыкладання"</string>
     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Пераключыць прыкладанні?"</string>
     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Ужо запушчана іншае прыкладанне, якое павінна быць спынена перад запускам новага."</string>
     <string name="old_app_action" msgid="493129172238566282">"Вярнуцца да <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -1081,7 +974,7 @@
     <string name="new_app_action" msgid="5472756926945440706">"Запусціць <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Спыніць старыя прыкладанні без захавання."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці"</string>
-    <string name="dump_heap_notification_detail" msgid="6901391084243999274">"Быў сабраны дамп кучы; дакраніцеся, каб абагуліць"</string>
+    <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Быў сабраны дамп кучы; дакраніцеся, каб абагуліць"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Абагуліць дамп дынамічнай вобласці?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"Працэс <xliff:g id="PROC">%1$s</xliff:g> перавысіў ліміт памяці працэсу <xliff:g id="SIZE">%2$s</xliff:g>. Дамп дынамічнай вобласці даступны для вас, вы можаце абагуліць яго з распрацоўшчыкам. Будзьце асцярожныя: гэты дамп дынамічнай вобласці можа ўтрымліваць асабістую інфармацыю, да якой маюць доступ праграмы."</string>
     <string name="sendText" msgid="5209874571959469142">"Выберыце дзеянне для тэкста"</string>
@@ -1099,8 +992,8 @@
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Гучнасць выкліка"</string>
     <string name="volume_icon_description_media" msgid="4217311719665194215">"Гучнасць прайгравальніка"</string>
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Гучнасць апавяшчэнняў"</string>
-    <string name="ringtone_default" msgid="3789758980357696936">"Стандартны рынгтон"</string>
-    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Стандартны рынгтон (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+    <string name="ringtone_default" msgid="3789758980357696936">"Рынгтон па змаўчаннi"</string>
+    <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Рынгтон па змаўчаннi (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
     <string name="ringtone_silent" msgid="7937634392408977062">"Няма"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Рынгтоны"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Невядомы рынгтон"</string>
@@ -1121,7 +1014,7 @@
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"У Wi-Fi няма доступу да Інтэрнэту"</string>
-    <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Дакраніцеся, каб убачыць параметры"</string>
+    <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Дакраніцеся, каб убачыць параметры"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Дазволіць падключэнне?"</string>
@@ -1131,7 +1024,7 @@
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Дакраніцеся, каб убачыць налады"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
     <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
     <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
@@ -1147,12 +1040,12 @@
     <string name="sms_control_title" msgid="7296612781128917719">"Адпраўка SMS"</string>
     <string name="sms_control_message" msgid="3867899169651496433">"Прыкладанне &lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; дасылае вялікую колькасць SMS-паведамленняў. Дазволіць гэтаму прыкладанню працягваць адпраўляць паведамленні?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Дазволіць"</string>
-    <string name="sms_control_no" msgid="625438561395534982">"Адмовіць"</string>
+    <string name="sms_control_no" msgid="625438561395534982">"Забараніць"</string>
     <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; хоча адправiць паведамленне на адрас &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Гэта "<b>"можа прывесці да спагнання аплаты"</b>" з рахунку вашага мабільнага тэлефона."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Гэта прывядзе да спагнання аплаты з рахунку вашага мабільнага тэлефона."</b></string>
     <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Адправiць"</string>
-    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Скасаваць"</string>
+    <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Адмена"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Захаваць мой выбар"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Пазней гэта можна змянiць у раздзеле \"Налады &gt; Прыкладаннi\""</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Заўсёды дазваляць"</string>
@@ -1168,8 +1061,8 @@
     <string name="carrier_app_dialog_not_now" msgid="6361378684292268027">"НЕ ЗАРАЗ"</string>
     <string name="carrier_app_notification_title" msgid="8921767385872554621">"Устаўлена новая SIM-карта"</string>
     <string name="carrier_app_notification_text" msgid="1132487343346050225">"Краніце, каб наладзіць"</string>
-    <string name="time_picker_dialog_title" msgid="8349362623068819295">"Задаць час"</string>
-    <string name="date_picker_dialog_title" msgid="5879450659453782278">"Задаць дату"</string>
+    <string name="time_picker_dialog_title" msgid="8349362623068819295">"Усталяваць час"</string>
+    <string name="date_picker_dialog_title" msgid="5879450659453782278">"Усталяваць дату"</string>
     <string name="date_time_set" msgid="5777075614321087758">"Задаць"</string>
     <string name="date_time_done" msgid="2507683751759308828">"Гатова"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"НОВАЕ: "</font></string>
@@ -1177,15 +1070,15 @@
     <string name="no_permissions" msgid="7283357728219338112">"Дазволу не патрабуецца"</string>
     <string name="perm_costs_money" msgid="4902470324142151116">"за гэта можа спаганяцца плата"</string>
     <string name="dlg_ok" msgid="7376953167039865701">"ОК"</string>
-    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Праз USB зараджаецца гэта прылада"</string>
+    <string name="usb_charging_notification_title" msgid="6895185153353640787">"Па USB зараджаецца гэта прыладу"</string>
     <string name="usb_supplying_notification_title" msgid="5310642257296510271">"Па USB падачецца сілкаванне падключанай прыладзе"</string>
     <string name="usb_mtp_notification_title" msgid="8396264943589760855">"USB для перадачы файлаў"</string>
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB для перадачы фота"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Падключаны да USB-прылады"</string>
-    <string name="usb_notification_message" msgid="3370903770828407960">"Дакраніцеся, каб атрымаць іншыя параметры."</string>
-    <string name="adb_active_notification_title" msgid="6729044778949189918">"Адладка па USB падключана"</string>
-    <string name="adb_active_notification_message" msgid="4948470599328424059">"Дакраніцеся, каб адключыць адладку па USB."</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Дакраніцеся, каб атрымаць больш параметраў."</string>
+    <string name="adb_active_notification_title" msgid="6729044778949189918">"Прылада адладкі USB падключана"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Націсніце, каб адключыць адладку USB."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Стварэнне справаздачы пра памылку…"</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Падзяліцца справаздачай пра памылку?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Перадача справаздачы пра памылку..."</string>
@@ -1205,9 +1098,9 @@
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Выяўлены новы носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Для перадачы фатаграфій і медыяфайлаў"</string>
     <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Пашкоджаны носьбіт <xliff:g id="NAME">%s</xliff:g>"</string>
-    <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"Носьбіт <xliff:g id="NAME">%s</xliff:g> пашкоджаны. Дакраніцеся, каб выправіць."</string>
+    <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Носьбіт <xliff:g id="NAME">%s</xliff:g> пашкоджаны. Дакраніцеся, каб выправіць."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"<xliff:g id="NAME">%s</xliff:g> не падтрымліваецца"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Гэта прылада не падтрымлівае носьбіт <xliff:g id="NAME">%s</xliff:g>. Дакраніцеся, каб наладзіць яго ў фармаце, які падтрымліваецца."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Гэта прылада не падтрымлівае носьбіт <xliff:g id="NAME">%s</xliff:g>. Дакраніцеся, каб наладзіць яго ў фармаце, які падтрымліваецца."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Носьбіт <xliff:g id="NAME">%s</xliff:g> нечакана выняты"</string>
     <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Адключыце носьбіт <xliff:g id="NAME">%s</xliff:g>, перш чым вымаць яго, каб пазбегнуць страты даных."</string>
     <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Носьбіт <xliff:g id="NAME">%s</xliff:g> выдалены"</string>
@@ -1243,7 +1136,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Дазваляе праграме счытваць сеансы ўсталёўкі. Гэта дазваляе ёй праглядаць інфармацыю аб актыўных усталёўках пакета."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"запытваць усталёўку пакетаў"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Дазваляе праграме запытваць усталёўку пакетаў."</string>
-    <string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Націсніце двойчы, каб кіраваць маштабаваннем"</string>
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Двойчы дакраніцеся, каб змянiць маштаб"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Немагчыма дадаць віджэт."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Пачаць"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Пошук"</string>
@@ -1258,7 +1151,7 @@
     <string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Дазволіць гэты запыт?"</string>
     <string name="grant_permissions_header_text" msgid="6874497408201826708">"Запыт на доступ"</string>
     <string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
-    <string name="deny" msgid="2081879885755434506">"Адмовіць"</string>
+    <string name="deny" msgid="2081879885755434506">"Забараніць"</string>
     <string name="permission_request_notification_title" msgid="6486759795926237907">"Дазвол запытаны"</string>
     <string name="permission_request_notification_with_subtitle" msgid="8530393139639560189">"Запытаны дазвол\nдля ўліковага запісу <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
     <string name="forward_intent_to_owner" msgid="1207197447013960896">"Вы выкарыстоўваеце гэту праграму па-за межамі свайго працоўнага профілю"</string>
@@ -1274,20 +1167,20 @@
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Служба ацэнкі важнасці апавяшчэнняў"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN актываваны"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"VPN актывуецца прыкладаннем <xliff:g id="APP">%s</xliff:g>"</string>
-    <string name="vpn_text" msgid="1610714069627824309">"Націсніце, каб кіраваць сеткай."</string>
-    <string name="vpn_text_long" msgid="4907843483284977618">"Падлучаны да <xliff:g id="SESSION">%s</xliff:g>. Націсніце, каб кiраваць сеткай."</string>
+    <string name="vpn_text" msgid="3011306607126450322">"Дакраніцеся, каб кіраваць сеткай."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Падлучаны да сеанса \"<xliff:g id="SESSION">%s</xliff:g>\". Дакраніцеся, каб кiраваць сеткай."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Падключэнне заўсёды ўключанага VPN..."</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Заўсёды ўключаны i падключаны VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Памылка заўсёды ўключанага VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Дакраніцеся, каб сканфігураваць"</string>
+    <string name="vpn_lockdown_config" msgid="6415899150671537970">"Націсніце, каб змяніць налады"</string>
     <string name="upload_file" msgid="2897957172366730416">"Выберыце файл"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Файл не выбраны"</string>
     <string name="reset" msgid="2448168080964209908">"Скінуць"</string>
     <string name="submit" msgid="1602335572089911941">"Перадаць"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Рэжым \"У машыне\" ўключаны"</string>
-    <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Дакраніцеся, каб выйсці з рэжыму \"У машыне\"."</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Дакраніцеся, каб выйсці з рэжыму \"Штурман\"."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"USB-мадэм або кропка доступу Wi-Fi актыўныя"</string>
-    <string name="tethered_notification_message" msgid="2113628520792055377">"Дакраніцеся, каб наладзіць."</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"Націсніце, каб наладзіць."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Назад"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Далей"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Прапусціць"</string>
@@ -1302,7 +1195,7 @@
     <string name="action_mode_done" msgid="7217581640461922289">"Гатова"</string>
     <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Выдаленне дадзеных з USB-назапашвальнiка..."</string>
     <string name="progress_erasing" product="default" msgid="6596988875507043042">"Выдаленне дадзеных з SD-карты..."</string>
-    <string name="share" msgid="1778686618230011964">"Абагуліць"</string>
+    <string name="share" msgid="1778686618230011964">"Адкрыць доступ"</string>
     <string name="find" msgid="4808270900322985960">"Пошук"</string>
     <string name="websearch" msgid="4337157977400211589">"Вэб-пошук"</string>
     <string name="find_next" msgid="5742124618942193978">"Знайсці нiжэй"</string>
@@ -1322,7 +1215,7 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Дадаць уліковы запіс"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Павялічыць"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"Паменшыць"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> – Націсніце і ўтрымлівайце."</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Націсніце і ўтрымлівайце <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Правядзіце пальцам уверх, каб павялічыць, або ўніз, каб паменшыць."</string>
     <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Павялічыць лічбу хвілін."</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Паменшыць лічбу хвілін."</string>
@@ -1339,7 +1232,7 @@
     <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Папярэдні месяц"</string>
     <string name="date_picker_next_month_button" msgid="5559507736887605055">"Наступны месяц"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Скасаваць"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Адмена"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Выдаліць"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Гатова"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Змена рэжыму"</string>
@@ -1366,7 +1259,7 @@
     <string name="storage_usb" msgid="3017954059538517278">"USB-назапашвальнік"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Рэдагаваць"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Папярэджанне выкарыстання дадзеных"</string>
-    <string name="data_usage_warning_body" msgid="6660692274311972007">"Прагляд выкарыстання і налад."</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"Дакраніцеся, каб прагледзець гісторыю выкарыстання і налады."</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Дасягнуты ліміт трафіку 2G-3G"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Дасягнуты ліміт трафіку 4G"</string>
     <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Дасягн. ліміт маб.перадачы даных"</string>
@@ -1378,14 +1271,14 @@
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Перав. ліміт па дадзеным Wi-Fi"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"Аб\'ём <xliff:g id="SIZE">%s</xliff:g> перавышае устаноўл. мяжу."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Зыходныя дадзеныя абмежаваныя"</string>
-    <string name="data_usage_restricted_body" msgid="469866376337242726">"Дакраніцеся, каб зняць абмежав."</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Націсніце, каб зняць абмежаванне."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Сертыфікат бяспекі"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Гэты сертыфікат сапраўдны."</string>
-    <string name="issued_to" msgid="454239480274921032">"Каму выдадзена:"</string>
+    <string name="issued_to" msgid="454239480274921032">"Выдадзены:"</string>
     <string name="common_name" msgid="2233209299434172646">"Звычайнае імя:"</string>
     <string name="org_name" msgid="6973561190762085236">"Арганізацыя:"</string>
     <string name="org_unit" msgid="7265981890422070383">"Аддзел арганізацыі:"</string>
-    <string name="issued_by" msgid="2647584988057481566">"Хто выдаў:"</string>
+    <string name="issued_by" msgid="2647584988057481566">"Выдана:"</string>
     <string name="validity_period" msgid="8818886137545983110">"Тэрмін дзеяння:"</string>
     <string name="issued_on" msgid="5895017404361397232">"Выдадзены:"</string>
     <string name="expires_on" msgid="3676242949915959821">"Заканчваецца:"</string>
@@ -1428,7 +1321,7 @@
     <string name="display_manager_overlay_display_title" msgid="652124517672257172">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> кр. на цалю"</string>
     <string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", бяспечны"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільны ўзор"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%1$d</xliff:g> с."</string>
@@ -1596,7 +1489,8 @@
     <string name="select_year" msgid="7952052866994196170">"Выберыце год"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Выдалена: <xliff:g id="KEY">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (праца)"</string>
-    <string name="lock_to_app_toast" msgid="1420543809500606964">"Каб адмацаваць гэты экран, дакраніцеся і ўтрымлівайце кнопку \"Назад\"."</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"Каб адмацаваць гэты экран, краніце і ўтрымлівайце кнопкі «Назад» і «Агляд» адначасова."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Каб адмацаваць гэты экран, краніце і ўтрымлівайце кнопку «Агляд»."</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>
@@ -1607,9 +1501,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Абноўлена вашым адміністратарам"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Выдалена вашым адміністратарам"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Каб падоўжыць час працы акумулятара, у рэжыме эканоміі зараду памяншаецца прадукцыйнасць вашай прылады, абмяжоўваецца выкарыстанне вібрацыі, службаў вызначэння месцазнаходжання і большасці задач фонавай перадачы даных. Электронная пошта, абмен паведамленнямі і іншыя праграмы, якія выкарыстоўваюць сінхранізацыю, могуць не абнаўляцца, пакуль вы іх не адкрыеце.\n\nРэжым эканоміі зараду адключаецца аўтаматычна, калі прылада зараджаецца."</string>
-    <string name="data_saver_description" msgid="6015391409098303235">"Каб паменшыць выкарыстанне даных, Эканомія трафіку не дазваляе некаторым праграмам адпраўляць ці атрымліваць даныя ў фонавым рэжыме. Праграма, якую вы зараз выкарыстоўваеце, можа атрымліваць доступ да даных, але можа рабіць гэта радзей. Гэта можа азначаць, напрыклад, што відарысы не паказваюцца, пакуль вы не дакраняцеся да іх."</string>
-    <string name="data_saver_enable_title" msgid="4674073932722787417">"Уключыць Эканомію трафіка?"</string>
-    <string name="data_saver_enable_button" msgid="7147735965247211818">"Уключыць"</string>
+    <!-- no translation found for data_saver_description (6015391409098303235) -->
+    <skip />
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">На %1$d хвіліну (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">На %1$d хвіліны (да <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1679,8 +1572,6 @@
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"Запыт SS зменены на запыт USSD."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"Запыт SS зменены на новы запыт SS."</string>
     <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Працоўны профіль"</string>
-    <string name="expand_button_content_description" msgid="5855955413376384681">"Кнопка \"Разгарнуць\""</string>
-    <string name="expand_action_accessibility" msgid="5307730695723718254">"разгарнуць/згарнуць"</string>
     <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Перыферыйны USB-порт Android"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"Перыферыйны USB-порт"</string>
@@ -1688,7 +1579,6 @@
     <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Закрыць лішак"</string>
     <string name="maximize_button_text" msgid="7543285286182446254">"Разгарнуць"</string>
     <string name="close_button_text" msgid="3937902162644062866">"Закрыць"</string>
-    <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
     <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> выбраны</item>
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> выбрана</item>
@@ -1723,5 +1613,4 @@
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Выканайце скід да заводскіх налад, каб выкарыстоўваць гэту прыладу без абмежаванняў"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Краніце, каб даведацца больш."</string>
-    <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Адключаны <xliff:g id="LABEL">%1$s</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index ef9d524..da70645 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Освобождаване"</string>
     <string name="app_info" msgid="6856026610594615344">"Информация за приложението"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Рестартиране на сесията"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Докоснете, за да стартирате нова демонстрационна сесия"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Демонстрацията се стартира"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Сесията се рестартира"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Възстановете фабричните настройки на това устройство, за да го използвате без ограничения"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Докоснете, за да научите повече."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>: Деактивирано"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 97e61c9..efae130 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"এখন"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>মি</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>মি</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>মিনিট</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>মিনিট</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ঘ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ঘ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ঘণ্টা</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ঘণ্টা</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>দি</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>দি</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>দিন</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>দিন</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ব</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ব</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>বছর</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>বছর</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>মি</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>মি</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>মিনিটের মধ্যে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>মিনিটের মধ্যে</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ঘ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ঘ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ঘন্টার মধ্যে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ঘন্টার মধ্যে</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>দি</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>দি</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>দিনের মধ্যে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>দিনের মধ্যে</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ব</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ব</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>বছরের মধ্যে</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>বছরের মধ্যে</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>মিনিট আগে</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"আনপিন করুন"</string>
     <string name="app_info" msgid="6856026610594615344">"অ্যাপ্লিকেশানের তথ্য"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"সেশন পুনঃসূচনা করুন"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"একটি নতুন ডেমো সেশন শুরু করতে আলতো চাপ দিন"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ডেমো শুরু করা হচ্ছে"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"সেশন পুনরায় চালু করা হচ্ছে"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"কোনো বিধিনিষেধ ছাড়াই এই ডিভাইসটিকে ব্যবহার করতে ফ্যাক্টরি রিসেট করুন"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"আরো জানতে স্পর্শ করুন৷"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-bs-rBA/strings.xml b/core/res/res/values-bs-rBA/strings.xml
index bd14448..8b0a04a 100644
--- a/core/res/res/values-bs-rBA/strings.xml
+++ b/core/res/res/values-bs-rBA/strings.xml
@@ -125,15 +125,11 @@
     <string name="roamingTextSearching" msgid="8360141885972279963">"Traženje usluge"</string>
     <string name="wfcRegErrorTitle" msgid="2301376280632110664">"Wi-Fi pozivanje"</string>
   <string-array name="wfcOperatorErrorAlertMessages">
-    <item msgid="2254967670088539682">"Da biste pozivali i slali poruke preko Wi-Fi-ja, prvo zatražite od operatera da postavi tu uslugu. Potom u Postavkama ponovo uključite Wi-Fi pozivanje."</item>
   </string-array>
   <string-array name="wfcOperatorErrorNotificationMessages">
-    <item msgid="6177300162212449033">"Registrirajte se kod svog operatera"</item>
   </string-array>
-  <string-array name="wfcSpnFormats">
-    <item msgid="6830082633573257149">"%s"</item>
-    <item msgid="4397097370387921767">"Wi-Fi pozivanje preko operatera %s"</item>
-  </string-array>
+    <string name="wfcSpnFormat" msgid="8211621332478306568">"%s"</string>
+    <string name="wfcDataSpnFormat" msgid="1118052028767666883">"%s"</string>
     <string name="wifi_calling_off_summary" msgid="8720659586041656098">"Isključeno"</string>
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Prednost ima Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Prednost ima mobilna mreža"</string>
@@ -169,11 +165,7 @@
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Prostor za gledanje je pun. Obrišite neke fajlove da oslobodite prostor."</string>
     <string name="low_memory" product="tv" msgid="516619861191025923">"Prostor TV-a za pohranu je pun. Obrišite neke fajlove da oslobodite prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Pohrana telefona je puna. Izbrišite fajlove kako biste oslobodili prostor."</string>
-    <plurals name="ssl_ca_cert_warning" formatted="false" msgid="5106721205300213569">
-      <item quantity="one">Instalirane su ustanove za izdavanje certifikata</item>
-      <item quantity="few">Instalirane su ustanove za izdavanje certifikata</item>
-      <item quantity="other">Instalirane su ustanove za izdavanje certifikata</item>
-    </plurals>
+    <!-- no translation found for ssl_ca_cert_warning (5106721205300213569) -->
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od nepoznate treće strane"</string>
     <string name="ssl_ca_cert_noti_by_administrator" msgid="550758088185764312">"od strane administratora vašeg profila za posao"</string>
     <string name="ssl_ca_cert_noti_managed" msgid="4030263497686867141">"Od <xliff:g id="MANAGING_DOMAIN">%s</xliff:g>"</string>
@@ -220,9 +212,9 @@
     <string name="bugreport_title" msgid="2667494803742548533">"Kreirajte izvještaj o greškama"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ovim će se prikupljati informacije o trenutnom stanju uređaja, koji će biti poslani kao poruka e-pošte. Može malo potrajati dok se izvještaj o greškama ne kreira i bude spreman za slanje. Budite strpljivi."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Interaktivni izvještaj"</string>
-    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Koristite ovu opciju u većini slučajeva. Ova opcija vam omogućava praćenje napretka izvještaja, unos dodatnih detalja o problemu i pravljenje snimaka ekrana. Moglo bi doći do izostavljanja nekih manje korištenih dijelova za čije prijavljivanje je potrebno dugo vremena."</string>
+    <string name="bugreport_option_interactive_summary" msgid="8180152634022797629">"Koristite ovo u većini slučajeva. Omogućava vam praćenje progresa izvještaja i unošenje više detalja o datom problemu. Neke manje korištene oblasti za čiji izvještaj je potrebno mnogo vremena mogu biti izostavljene."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"Kompletan izvještaj"</string>
-    <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Koristite ovu opciju za minimalno ometanje sistema kada uređaj ne reagira ili je prespor, ili kada su vam potrebni svi dijelovi izvještaja. Ova opcija ne dozvoljava unos dodatnih detalja ili pravljenje dodatnih snimaka ekrana."</string>
+    <string name="bugreport_option_full_summary" msgid="6687306111256813257">"Koristite ovu opciju za minimalno ometanje sistema kad uređaj ne reaguje ili je prespor, ili kada su vam potrebni svi odjeljci izvještaja. Opcija ne uzima snimku ekrana i ne dozvoljava unošenje više detalja."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
       <item quantity="one">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekundu.</item>
       <item quantity="few">Snimak ekrana za prijavu greške pravim za <xliff:g id="NUMBER_1">%d</xliff:g> sekunde.</item>
@@ -266,7 +258,7 @@
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Ponovo prikaži sadržaj prozora"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Istražite sadržaj prozora koji trenutno koristite."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključite Istraživanje dodirom"</string>
-    <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Stavke koje dodirnete bit će izgovorene naglas, a ekran možete istraživati koristeći pokrete."</string>
+    <string name="capability_desc_canRequestTouchExploration" msgid="5800552516779249356">"Stavke koje dotaknete će biti izgovorene naglas, a ekran možete istražiti pokretima"</string>
     <string name="capability_title_canRequestEnhancedWebAccessibility" msgid="1739881766522594073">"Uključite poboljšanu web pristupačnost"</string>
     <string name="capability_desc_canRequestEnhancedWebAccessibility" msgid="7881063961507511765">"Možda će biti instalirana skripta kako bi sadržaj aplikacije bio dostupniji."</string>
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Obratite pažnju na tekst koji tipkate"</string>
@@ -665,7 +657,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"Unesite PUK i novi PIN"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"Novi PIN"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"Dodirnite za unos lozinke"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"Dodirnite za unos lozinke"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"Unesite lozinku za otključavanje tipkovnice"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Unesite PIN za otključavanje tipkovnice"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Pogrešan PIN."</string>
@@ -865,87 +857,6 @@
       <item quantity="few"><xliff:g id="COUNT">%d</xliff:g> sata</item>
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> sati</item>
     </plurals>
-    <string name="now_string_shortest" msgid="8912796667087856402">"sada"</string>
-    <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>m</item>
-    </plurals>
-    <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
-    </plurals>
-    <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
-    </plurals>
-    <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>g</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>g</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>g</item>
-    </plurals>
-    <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g>m</item>
-    </plurals>
-    <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-    </plurals>
-    <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g>d</item>
-    </plurals>
-    <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one">za <xliff:g id="COUNT_1">%d</xliff:g> g</item>
-      <item quantity="few">za <xliff:g id="COUNT_1">%d</xliff:g> g</item>
-      <item quantity="other">za <xliff:g id="COUNT_1">%d</xliff:g> g</item>
-    </plurals>
-    <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
-      <item quantity="one"> Prije <xliff:g id="COUNT_1">%d</xliff:g> minutu</item>
-      <item quantity="few"> Prije <xliff:g id="COUNT_1">%d</xliff:g> minute</item>
-      <item quantity="other"> Prije <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-    </plurals>
-    <plurals name="duration_hours_relative" formatted="false" msgid="676894109982008411">
-      <item quantity="one"> Prije <xliff:g id="COUNT_1">%d</xliff:g> sat</item>
-      <item quantity="few"> Prije <xliff:g id="COUNT_1">%d</xliff:g> sata</item>
-      <item quantity="other"> Prije <xliff:g id="COUNT_1">%d</xliff:g> sati</item>
-    </plurals>
-    <plurals name="duration_days_relative" formatted="false" msgid="2203515825765397130">
-      <item quantity="one"> Prije <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="few"> Prije <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-      <item quantity="other"> Prije <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-    </plurals>
-    <plurals name="duration_years_relative" formatted="false" msgid="4820062134188885734">
-      <item quantity="one"> Prije <xliff:g id="COUNT_1">%d</xliff:g> godinu</item>
-      <item quantity="few"> Prije <xliff:g id="COUNT_1">%d</xliff:g> godine</item>
-      <item quantity="other"> Prije <xliff:g id="COUNT_1">%d</xliff:g> godina</item>
-    </plurals>
-    <plurals name="duration_minutes_relative_future" formatted="false" msgid="4655043589817680966">
-      <item quantity="one"> za <xliff:g id="COUNT_1">%d</xliff:g> minutu</item>
-      <item quantity="few"> za <xliff:g id="COUNT_1">%d</xliff:g> minute</item>
-      <item quantity="other"> za <xliff:g id="COUNT_1">%d</xliff:g> minuta</item>
-    </plurals>
-    <plurals name="duration_hours_relative_future" formatted="false" msgid="8084579714205223891">
-      <item quantity="one"> za <xliff:g id="COUNT_1">%d</xliff:g> sat</item>
-      <item quantity="few"> za <xliff:g id="COUNT_1">%d</xliff:g> sata</item>
-      <item quantity="other"> za <xliff:g id="COUNT_1">%d</xliff:g> sati</item>
-    </plurals>
-    <plurals name="duration_days_relative_future" formatted="false" msgid="333215369363433992">
-      <item quantity="one"> za <xliff:g id="COUNT_1">%d</xliff:g> dan</item>
-      <item quantity="few"> za <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-      <item quantity="other"> za <xliff:g id="COUNT_1">%d</xliff:g> dana</item>
-    </plurals>
-    <plurals name="duration_years_relative_future" formatted="false" msgid="8644862986413104011">
-      <item quantity="one"> za <xliff:g id="COUNT_1">%d</xliff:g> godinu</item>
-      <item quantity="few"> za <xliff:g id="COUNT_1">%d</xliff:g> godine</item>
-      <item quantity="other"> za <xliff:g id="COUNT_1">%d</xliff:g> godina</item>
-    </plurals>
     <string name="VideoView_error_title" msgid="3534509135438353077">"Problem sa prikazom video sadržaja"</string>
     <string name="VideoView_error_text_invalid_progressive_playback" msgid="3186670335938670444">"Prijenos ovog video sadržaja ne može se izvršiti na ovom uređaju."</string>
     <string name="VideoView_error_text_unknown" msgid="3450439155187810085">"Greška prilikom reproduciranja video sadržaja."</string>
@@ -977,11 +888,11 @@
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke funkcije sistema možda neće raditi"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno prostora za sistem. Obezbijedite 250MB slobodnog prostora i ponovo pokrenite uređaj."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
-    <string name="app_running_notification_text" msgid="1197581823314971177">"Dodirnite za više informacija ili da biste zaustavili aplikaciju."</string>
+    <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili da zaustavite aplikaciju."</string>
     <string name="ok" msgid="5970060430562524910">"Uredu"</string>
-    <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+    <string name="cancel" msgid="6442560571259935130">"Prekini"</string>
     <string name="yes" msgid="5362982303337969312">"Uredu"</string>
-    <string name="no" msgid="5141531044935541497">"Otkaži"</string>
+    <string name="no" msgid="5141531044935541497">"Prekini"</string>
     <string name="dialog_alert_title" msgid="2049658708609043103">"Pažnja"</string>
     <string name="loading" msgid="7933681260296021180">"Učitavanje..."</string>
     <string name="capital_on" msgid="1544682755514494298">"Uključeno"</string>
@@ -1019,7 +930,8 @@
     <string name="aerr_process" msgid="6201597323218674729">"<xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen"</string>
     <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"<xliff:g id="PROCESS">%1$s</xliff:g> se stalno zaustavlja"</string>
-    <string name="aerr_restart" msgid="7581308074153624475">"Ponovo otvori aplikaciju"</string>
+    <string name="aerr_restart" msgid="9001379185665886595">"Ponovo pokreni aplikaciju"</string>
+    <string name="aerr_reset" msgid="7645427603514220451">"Vrati aplikaciju na zadano i pokreni ponovo"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošalji povratne informacije"</string>
     <string name="aerr_close" msgid="2991640326563991340">"Zatvori"</string>
     <string name="aerr_mute" msgid="1974781923723235953">"Isključiti zvuk dok se uređaj ponovo ne pokrene"</string>
@@ -1045,14 +957,12 @@
     <string name="android_upgrading_title" msgid="1584192285441405746">"Nadogradnja sistema Android u toku..."</string>
     <string name="android_start_title" msgid="8418054686415318207">"Android se pokreće..."</string>
     <string name="android_upgrading_fstrim" msgid="8036718871534640010">"Optimiziranje pohrane."</string>
-    <string name="android_upgrading_notification_title" msgid="1619393112444671028">"Android se nadograđuje"</string>
-    <string name="android_upgrading_notification_body" msgid="5761201379457064286">"Neke aplikacije možda neće raditi ispravno dok traje nadogradnja"</string>
     <string name="android_upgrading_apk" msgid="7904042682111526169">"Optimiziranje aplikacije <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="android_preparing_apk" msgid="8162599310274079154">"Priprema se <xliff:g id="APPNAME">%1$s</xliff:g>."</string>
     <string name="android_upgrading_starting_apps" msgid="451464516346926713">"Pokretanje aplikacija."</string>
     <string name="android_upgrading_complete" msgid="1405954754112999229">"Pokretanje pri kraju."</string>
     <string name="heavy_weight_notification" msgid="9087063985776626166">"Pokrenuta je aplikacija <xliff:g id="APP">%1$s</xliff:g>"</string>
-    <string name="heavy_weight_notification_detail" msgid="867643381388543170">"Dodirnite da biste se prebacili na aplikaciju"</string>
+    <string name="heavy_weight_notification_detail" msgid="1721681741617898865">"Dodirnite kako biste otvorili aplikaciju"</string>
     <string name="heavy_weight_switcher_title" msgid="7153167085403298169">"Želite se prebaciti na drugu aplikaciju?"</string>
     <string name="heavy_weight_switcher_text" msgid="7022631924534406403">"Već je pokrenuta jedna aplikacija koju morate zaustaviti prije pokretanja nove."</string>
     <string name="old_app_action" msgid="493129172238566282">"Vrati se na aplikaciju <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -1060,7 +970,7 @@
     <string name="new_app_action" msgid="5472756926945440706">"Pokreni <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
     <string name="new_app_description" msgid="1932143598371537340">"Zaustaviti staru aplikaciju bez spašavanja podataka."</string>
     <string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> premašuje ograničenje memorije"</string>
-    <string name="dump_heap_notification_detail" msgid="6901391084243999274">"Snimak dinamičkog stanja memorije je napravljen; dodirnite da biste dijelili"</string>
+    <string name="dump_heap_notification_detail" msgid="2075673362317481664">"Snimak dinamičkog dijela memorije je napravljen; dodirnite za dijeljenje"</string>
     <string name="dump_heap_title" msgid="5864292264307651673">"Želite li dijeliti snimak dinamičkog dijela memorije?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"Proces <xliff:g id="PROC">%1$s</xliff:g> je premašio ograničenje procesne memorije od <xliff:g id="SIZE">%2$s</xliff:g>. Snimak dinamičkog dijela memorije vam je dostupan i možete ga dijeliti sa njegovim programerom. Budite oprezni: ovaj snimak dinamičkog dijela memorije može sadržavati vaše lične podatke kojima aplikacija ima pristup."</string>
     <string name="sendText" msgid="5209874571959469142">"Biranje akcije za tekst"</string>
@@ -1080,7 +990,7 @@
     <string name="volume_icon_description_notification" msgid="7044986546477282274">"Jačina zvuka za obavještenja"</string>
     <string name="ringtone_default" msgid="3789758980357696936">"Zadana melodija zvona"</string>
     <string name="ringtone_default_with_actual" msgid="8129563480895990372">"Zadano zvono (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
-    <string name="ringtone_silent" msgid="7937634392408977062">"Bez zvuka"</string>
+    <string name="ringtone_silent" msgid="7937634392408977062">"Ne poduzimaj ništa"</string>
     <string name="ringtone_picker_title" msgid="3515143939175119094">"Melodije zvona"</string>
     <string name="ringtone_unknown" msgid="5477919988701784788">"Nepoznato zvono"</string>
     <plurals name="wifi_available" formatted="false" msgid="7900333017752027322">
@@ -1098,7 +1008,7 @@
     <!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
     <skip />
     <string name="wifi_no_internet" msgid="8451173622563841546">"Wi-Fi nema pristup Internetu"</string>
-    <string name="wifi_no_internet_detailed" msgid="8083079241212301741">"Dodirnite za opcije"</string>
+    <string name="wifi_no_internet_detailed" msgid="7593858887662270131">"Dodirnite za opcije"</string>
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Problem prilikom spajanja na Wi-Fi mrežu"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internet vezu."</string>
     <string name="wifi_connect_alert_title" msgid="8455846016001810172">"Želite li dozvoliti povezivanje?"</string>
@@ -1108,7 +1018,7 @@
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni Wi-Fi Direct. To će isključiti Wi-Fi klijenta/pristupnu tačku."</string>
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Greška u pokretanju opcije Wi-Fi Direct."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je uključen"</string>
-    <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Dodirnite za postavke"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvati"</string>
     <string name="decline" msgid="2112225451706137894">"Odbijte"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica poslana"</string>
@@ -1160,9 +1070,9 @@
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB za prijenos slika"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Uspostavljena veza sa USB pohranom"</string>
-    <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Dodirnite za više opcija."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Uređaj za USB otklanjanje grešaka povezan"</string>
-    <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da onemogućite otklanjanje grešaka preko USB veze."</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"Dodirnite da biste onemogućili USB otklanjanje grešaka."</string>
     <string name="taking_remote_bugreport_notification_title" msgid="6742483073875060934">"Prijem izvještaja o grešci..."</string>
     <string name="share_remote_bugreport_notification_title" msgid="4987095013583691873">"Podijeliti izvještaj o grešci?"</string>
     <string name="sharing_remote_bugreport_notification_title" msgid="7572089031496651372">"Dijeljenje izvještaja o grešci..."</string>
@@ -1182,9 +1092,9 @@
     <string name="ext_media_new_notification_message" msgid="7589986898808506239">"Novi uređaj <xliff:g id="NAME">%s</xliff:g> je otkriven"</string>
     <string name="ext_media_ready_notification_message" msgid="4083398150380114462">"Za prebacivanje slika i medijskih fajlova"</string>
     <string name="ext_media_unmountable_notification_title" msgid="8295123366236989588">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen"</string>
-    <string name="ext_media_unmountable_notification_message" msgid="2343202057122495773">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da biste popravili."</string>
+    <string name="ext_media_unmountable_notification_message" msgid="1586311304430052169">"Uređaj <xliff:g id="NAME">%s</xliff:g> je oštećen. Dodirnite da ga popravite."</string>
     <string name="ext_media_unsupported_notification_title" msgid="3797642322958803257">"Uređaj <xliff:g id="NAME">%s</xliff:g> nije podržan"</string>
-    <string name="ext_media_unsupported_notification_message" msgid="6121601473787888589">"Ovaj uređaj ne podržava uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da biste ga postavili u podržanom formatu."</string>
+    <string name="ext_media_unsupported_notification_message" msgid="8789610369456474891">"Ovaj uređaj ne podržava uređaj <xliff:g id="NAME">%s</xliff:g>. Dodirnite da ga postavite u podržanom formatu."</string>
     <string name="ext_media_badremoval_notification_title" msgid="3206248947375505416">"Neočekivano uklonjen uređaj <xliff:g id="NAME">%s</xliff:g>"</string>
     <string name="ext_media_badremoval_notification_message" msgid="380176703346946313">"Isključite uređaj <xliff:g id="NAME">%s</xliff:g> prije uklanjanja da izbjegnete gubitak podataka"</string>
     <string name="ext_media_nomedia_notification_title" msgid="1704840188641749091">"Uređaj <xliff:g id="NAME">%s</xliff:g> je uklonjen"</string>
@@ -1220,8 +1130,7 @@
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Dozvoljava aplikaciji da čita sesije instalacija. Ovim se aplikaciji omogućava da vidi detalje o aktivnim instalacijama paketa."</string>
     <string name="permlab_requestInstallPackages" msgid="5782013576218172577">"zahtijevanje paketa za instaliranje"</string>
     <string name="permdesc_requestInstallPackages" msgid="5740101072486783082">"Omogućava aplikaciji da zahtijeva instalaciju paket ā."</string>
-    <!-- no translation found for tutorial_double_tap_to_zoom_message_short (1311810005957319690) -->
-    <skip />
+    <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Dodirnite dvaput za kontrolu uvećavanja"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Dodavanje vidžeta nije uspjelo."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"Počni"</string>
     <string name="ime_action_search" msgid="658110271822807811">"Traži"</string>
@@ -1252,22 +1161,20 @@
     <string name="notification_ranker_binding_label" msgid="774540592299064747">"Usluga rangiranja obavještenja"</string>
     <string name="vpn_title" msgid="19615213552042827">"VPN aktiviran"</string>
     <string name="vpn_title_long" msgid="6400714798049252294">"Aplikacija <xliff:g id="APP">%s</xliff:g> je aktivirala VPN"</string>
-    <!-- no translation found for vpn_text (1610714069627824309) -->
-    <skip />
-    <!-- no translation found for vpn_text_long (4907843483284977618) -->
-    <skip />
+    <string name="vpn_text" msgid="3011306607126450322">"Dodirnite za upravljanje mrežom."</string>
+    <string name="vpn_text_long" msgid="6407351006249174473">"Uspostavljena veza sa <xliff:g id="SESSION">%s</xliff:g>. Dodirnite za upravljanje mrežom."</string>
     <string name="vpn_lockdown_connecting" msgid="6443438964440960745">"Povezivanje na uvijek aktivni VPN…"</string>
     <string name="vpn_lockdown_connected" msgid="8202679674819213931">"Povezan na uvijek aktivni VPN"</string>
     <string name="vpn_lockdown_error" msgid="6009249814034708175">"Greška u povezivanju na uvijek aktivni VPN"</string>
-    <string name="vpn_lockdown_config" msgid="4655589351146766608">"Dodirnite za konfiguriranje"</string>
+    <string name="vpn_lockdown_config" msgid="6415899150671537970">"Dodirnite da konfigurirate"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
     <string name="reset" msgid="2448168080964209908">"Ponovno pokretanje"</string>
     <string name="submit" msgid="1602335572089911941">"Potvrdi"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Način rada u autu omogućen"</string>
-    <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Dodirnite za izlaz iz načina rada u automobilu"</string>
+    <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Dodirnite kako biste izašli iz načina rada u autu."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Uređaj dijeli vezu ili djeluje kao pristupna tačka"</string>
-    <string name="tethered_notification_message" msgid="2113628520792055377">"Dodirnite za postavke"</string>
+    <string name="tethered_notification_message" msgid="6857031760103062982">"Dodirnite za postavljanje."</string>
     <string name="back_button_label" msgid="2300470004503343439">"Nazad"</string>
     <string name="next_button_label" msgid="1080555104677992408">"Naprijed"</string>
     <string name="skip_button_label" msgid="1275362299471631819">"Preskoči"</string>
@@ -1301,7 +1208,7 @@
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodajte račun"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećaj"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"Smanji"</string>
-    <string name="number_picker_increment_scroll_mode" msgid="5259126567490114216">"<xliff:g id="VALUE">%s</xliff:g> dodirnite i držite."</string>
+    <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Dodirnite <xliff:g id="VALUE">%s</xliff:g> i držite."</string>
     <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Kliznite gore da povećate i dolje da smanjite."</string>
     <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Povećaj minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Smanji minute"</string>
@@ -1318,7 +1225,7 @@
     <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Prethodni mjesec"</string>
     <string name="date_picker_next_month_button" msgid="5559507736887605055">"Sljedeći mjesec"</string>
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
-    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Otkaži"</string>
+    <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Prekini"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Izbriši"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Gotovo"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Promjena načina rada"</string>
@@ -1345,7 +1252,7 @@
     <string name="storage_usb" msgid="3017954059538517278">"USB pohrana"</string>
     <string name="extract_edit_menu_button" msgid="8940478730496610137">"Uredi"</string>
     <string name="data_usage_warning_title" msgid="1955638862122232342">"Upozorenje za prijenos podataka"</string>
-    <string name="data_usage_warning_body" msgid="6660692274311972007">"Dodirnite za prikaz upotrebe i postavki."</string>
+    <string name="data_usage_warning_body" msgid="2814673551471969954">"Podaci o korištenju i postavke"</string>
     <string name="data_usage_3g_limit_title" msgid="4361523876818447683">"Dostignut limit za 2G-3G podatke"</string>
     <string name="data_usage_4g_limit_title" msgid="4609566827219442376">"Dostignut limit za 4G podatke"</string>
     <string name="data_usage_mobile_limit_title" msgid="557158376602636112">"Dostignut limit mob. podataka"</string>
@@ -1357,7 +1264,7 @@
     <string name="data_usage_wifi_limit_snoozed_title" msgid="8743856006384825974">"Premašeno Wi-Fi ograničenje"</string>
     <string name="data_usage_limit_snoozed_body" msgid="7035490278298441767">"<xliff:g id="SIZE">%s</xliff:g> preko navedenog ograničenja."</string>
     <string name="data_usage_restricted_title" msgid="5965157361036321914">"Pozadinski podaci su ograničeni"</string>
-    <string name="data_usage_restricted_body" msgid="469866376337242726">"Dodirnite da biste uklonili ograničenja."</string>
+    <string name="data_usage_restricted_body" msgid="6741521330997452990">"Dodirnuti za uklanjanje ogran."</string>
     <string name="ssl_certificate" msgid="6510040486049237639">"Sigurnosni certifikat"</string>
     <string name="ssl_certificate_is_valid" msgid="6825263250774569373">"Ovaj certifikat je važeći."</string>
     <string name="issued_to" msgid="454239480274921032">"Primalac:"</string>
@@ -1574,7 +1481,8 @@
     <string name="select_year" msgid="7952052866994196170">"Odaberite godinu"</string>
     <string name="deleted_key" msgid="7659477886625566590">"Broj <xliff:g id="KEY">%1$s</xliff:g> je izbrisan"</string>
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"Poslovni <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="1420543809500606964">"Da biste otkačili ovaj ekran, dodirnite i držite dugme Nazad."</string>
+    <string name="lock_to_app_toast" msgid="7570091317001980053">"Da otkačite ovaj ekran, istovremeno dodirnite i držite Nazad i Pregled."</string>
+    <string name="lock_to_app_toast_accessible" msgid="8239120109365070664">"Da otkačite ovaj ekran, dodirnite i držite Pregled."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"Aplikacija je prikačena. Na ovom uređaju nije dozvoljeno otkačivanje."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Ekran je zakačen"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Ekran je otkačen"</string>
@@ -1585,9 +1493,8 @@
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Ažurirao administrator"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Izbrisao administrator"</string>
     <string name="battery_saver_description" msgid="1960431123816253034">"Da bi se trajanje baterije produžilo, opcija za štednju baterije minimizira rad uređaja i ograničava vibriranje, usluge lokacije i većinu prijenosa podataka u pozadini. E-pošta, poruke i druge aplikacije koje se oslanjaju na sinhronizaciju ne mogu biti ažurirane dok ih ne otvorite.\n\nŠtednja baterije se automatski isključi prilikom punjenja uređaja."</string>
-    <string name="data_saver_description" msgid="6015391409098303235">"Da bi se smanjilo korištenje podataka, usluga Ušteda podataka sprečava da neke aplikacije šalju ili primaju podatke u pozadini. Aplikacija koju trenutno koristite može pristupiti podacima, ali se to može desiti rjeđe. To može značiti, naprimjer, da se slike ne prikazuju sve dok ih ne dodirnete."</string>
-    <string name="data_saver_enable_title" msgid="4674073932722787417">"Uključiti Uštedu podataka?"</string>
-    <string name="data_saver_enable_button" msgid="7147735965247211818">"Uključi"</string>
+    <!-- no translation found for data_saver_description (6015391409098303235) -->
+    <skip />
     <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="4367877408072000848">
       <item quantity="one">%1$d minuta (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
       <item quantity="few">%1$d minute (do <xliff:g id="FORMATTEDTIME_1">%2$s</xliff:g>)</item>
@@ -1649,8 +1556,6 @@
     <string name="stk_cc_ss_to_ussd" msgid="3951862188105305589">"SS zahtjev je izmijenjen u USSD zahtjev."</string>
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS zahtjev je izmijenjen u novi SS zahtjev."</string>
     <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil za posao"</string>
-    <string name="expand_button_content_description" msgid="5855955413376384681">"Dugme za proširivanje"</string>
-    <string name="expand_action_accessibility" msgid="5307730695723718254">"prebaci na proširenje"</string>
     <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB ulaz za periferijske uređaje"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB ulaz za periferijske uređaje"</string>
@@ -1658,7 +1563,6 @@
     <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Zatvori preklopni meni"</string>
     <string name="maximize_button_text" msgid="7543285286182446254">"Povećaj maksimalno"</string>
     <string name="close_button_text" msgid="3937902162644062866">"Zatvori"</string>
-    <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
     <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> stavka je odabrana</item>
       <item quantity="few"><xliff:g id="COUNT_1">%1$d</xliff:g> stavke su odabrane</item>
@@ -1692,5 +1596,4 @@
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Vratite uređaj na fabričke postavke kako biste ga koristili bez ograničenja"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da saznate više."</string>
-    <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 44a8f3b..458e810 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"No fixis"</string>
     <string name="app_info" msgid="6856026610594615344">"Informació de l\'aplicació"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Torna a iniciar la sessió"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toca per iniciar una nova sessió de demostració"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"S\'està iniciant la demostració"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"S\'està tornant a iniciar la sessió"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Restableix les dades de fàbrica del dispositiu per utilitzar-lo sense restriccions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca per obtenir més informació."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index ba33ccd..214f234d13 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Odepnout"</string>
     <string name="app_info" msgid="6856026610594615344">"Informace o aplikaci"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Restartujte relaci"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Klepnutím zahájíte novou demonstrační relaci"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Spouštění ukázky"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Restartování relace"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Chcete-li toto zařízení používat bez omezení, obnovte jej do továrního nastavení"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím zobrazíte další informace."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 6cd8d9f..e68003c 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Frigør"</string>
     <string name="app_info" msgid="6856026610594615344">"Oplysninger om appen"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Genstart sessionen"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tryk for at starte en ny demosession"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Starter demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Genstarter session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Gendan fabriksdataene på enheden for at bruge den uden begrænsninger"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryk for at få flere oplysninger."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 92541f2..80b1fad 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Markierung entfernen"</string>
     <string name="app_info" msgid="6856026610594615344">"App-Informationen"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Sitzung neu starten"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Zum Starten einer neuen Demositzung tippen"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo wird gestartet"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sitzung wird neu gestartet"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Gerät auf Werkseinstellungen zurücksetzen, um es ohne Einschränkungen zu nutzen"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Für weitere Informationen tippen."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 49ba0cf..af05afb 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -253,7 +253,7 @@
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Αποθηκευτικός χώρος"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"έχει πρόσβαση στις φωτογραφίες/πολυμέσα/αρχεία στη συσκευή σας"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Μικρόφωνο"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ηχογραφεί"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"εγγραφή ήχου"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Κάμερα"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"γίνεται λήψη φωτογραφιών και εγγραφή βίντεο"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Τηλέφωνο"</string>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Ξεκαρφίτσωμα"</string>
     <string name="app_info" msgid="6856026610594615344">"Πληροφορίες εφαρμογής"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Επανεκκίνηση περιόδου σύνδεσης"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Πατήστε για να ξεκινήσετε μια νέα περίοδο σύνδεσης επίδειξης"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Έναρξη επίδειξης"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Επανεκκίνηση περιόδου σύνδεσης"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Επαναφέρετε τις εργοστασιακές ρυθμίσεις για να χρησιμοποιήσετε αυτήν τη συσκευή χωρίς περιορισμούς"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Αγγίξτε για να μάθετε περισσότερα."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Απενεργοποιημένο <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 2f9fb4b..12c5e22 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Restart Session"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tap to start a new demo session"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Starting demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Restarting session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 2f9fb4b..12c5e22 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Restart Session"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tap to start a new demo session"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Starting demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Restarting session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 2f9fb4b..12c5e22 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"App info"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Restart Session"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tap to start a new demo session"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Starting demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Restarting session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Factory reset to use this device without restrictions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touch to find out more."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 393b8ff..e0281c9 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información de la app"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sesión"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Presiona para iniciar una nueva sesión de demostración"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Iniciando demostración"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reiniciando sesión"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece la configuración de fábrica para usar este dispositivo sin restricciones"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 89efca1..ae916ca 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"No fijar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información de la aplicación"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sesión"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toca para iniciar una nueva sesión de demostración"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Iniciando demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reiniciando sesión"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablece los datos de fábrica para usar este dispositivo sin restricciones"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para obtener más información."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index d8f6773..15c9d83 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Vabasta"</string>
     <string name="app_info" msgid="6856026610594615344">"Rakenduse teave"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Seansi taaskäivitamine"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Puudutage uue demoseansi alustamiseks"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo käivitamine"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Seansi taaskäivitamine"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Seadme piiranguteta kasutamiseks lähtestage see tehaseandmetele"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lisateabe saamiseks puudutage."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 6e5b178..655b7b7 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -1425,7 +1425,7 @@
     <string name="user_switched" msgid="3768006783166984410">"Uneko erabiltzailea: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailera aldatzen…"</string>
     <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen saioa amaitzen…"</string>
-    <string name="owner_name" msgid="2716755460376028154">"jabea"</string>
+    <string name="owner_name" msgid="2716755460376028154">"Jabea"</string>
     <string name="error_message_title" msgid="4510373083082500195">"Errorea"</string>
     <string name="error_message_change_not_allowed" msgid="1347282344200417578">"Zure administratzaileak ez du aldaketa egiteko baimena eman"</string>
     <string name="app_not_found" msgid="3429141853498927379">"Ez da ekintza gauza dezakeen aplikaziorik aurkitu"</string>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Kendu aingura"</string>
     <string name="app_info" msgid="6856026610594615344">"Aplikazioari buruzko informazioa"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Berrabiarazi saioa"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Demo-saio berria hasteko, sakatu hau"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demoa abiarazten"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Saioa berrabiarazten"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Berrezarri jatorrizko ezarpenak gailua murriztapenik gabe erabili ahal izateko"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sakatu informazio gehiago lortzeko."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 01b636d..0f61271 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"اکنون"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>دقیقه</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>دقیقه</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> دقیقه</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> دقیقه</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ساعت</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ساعت</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ساعت</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ساعت</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>روز</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>روز</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> روز</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> روز</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>سال</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>سال</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> سال</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> سال</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g>دقیقه</item>
-      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g>دقیقه</item>
+      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> دقیقه</item>
+      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> دقیقه</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g>ساعت</item>
-      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g>ساعت</item>
+      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> ساعت</item>
+      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> ساعت</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g>روز</item>
-      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g>روز</item>
+      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> روز</item>
+      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> روز</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g>سال</item>
-      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g>سال</item>
+      <item quantity="one">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
+      <item quantity="other">در <xliff:g id="COUNT_1">%d</xliff:g> سال</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> دقیقه پیش</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"برداشتن پین"</string>
     <string name="app_info" msgid="6856026610594615344">"اطلاعات برنامه"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"راه‌اندازی مجدد جلسه"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"برای شروع جلسه آزمایشی جدید ضربه بزنید"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"شروع نسخه نمایشی"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"راه‌اندازی مجدد جلسه"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"برای استفاده بدون محدودیت از این دستگاه، بازنشانی کارخانه‌ای انجام دهید"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"برای یادگیری بیشتر لمس کنید."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> غیرفعال شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e59165e..4441c81 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -876,20 +876,20 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> v</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min päästä</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min päästä</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min:n päästä</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min:n päästä</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> t päästä</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> t päästä</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> t:n päästä</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> t:n päästä</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> pv päästä</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> pv päästä</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> pv:n päästä</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> pv:n päästä</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> v päästä</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> v päästä</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> v:n päästä</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> v:n päästä</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> minuuttia sitten</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Irrota"</string>
     <string name="app_info" msgid="6856026610594615344">"Sovelluksen tiedot"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Istunnon uudelleenaloitus"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Aloita uusi esittely napauttamalla."</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Aloitetaan esittelyä"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Aloitetaan istuntoa uudelleen"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Palauta tehdasasetukset, jotta voit käyttää tätä laitetta rajoituksitta"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Lue lisätietoja koskettamalla."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 20d4e8a..9c8ff18 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1610,7 +1610,7 @@
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"La demande SS a été modifiée et est maintenant une nouvelle demande SS."</string>
     <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Profil professionnel"</string>
     <string name="expand_button_content_description" msgid="5855955413376384681">"Bouton Développer"</string>
-    <string name="expand_action_accessibility" msgid="5307730695723718254">"activer/désactiver le développement"</string>
+    <string name="expand_action_accessibility" msgid="5307730695723718254">"basculer le développement"</string>
     <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Port USB de l\'appareil Android"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"Port USB"</string>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Annuler l\'épinglage"</string>
     <string name="app_info" msgid="6856026610594615344">"Détails de l\'application"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Redémarrer la séance"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Touchez ici pour démarrer une nouvelle séance de démonstration"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Démarrage de la démonstration en cours..."</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Redémarrage de la séance en cours..."</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablissez la configuration d\'usine de cet appareil pour l\'utiliser sans restrictions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Touchez ici pour en savoir plus."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index b7daaf4..823803c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -860,8 +860,8 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"mainten."</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
@@ -876,8 +876,8 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> a</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">dans <xliff:g id="COUNT_1">%d</xliff:g> m</item>
-      <item quantity="other">dans <xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one">dans <xliff:g id="COUNT_1">%d</xliff:g> min</item>
+      <item quantity="other">dans <xliff:g id="COUNT_1">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
       <item quantity="one">dans <xliff:g id="COUNT_1">%d</xliff:g> h</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Retirer"</string>
     <string name="app_info" msgid="6856026610594615344">"Infos sur l\'appli"</string>
     <string name="negative_duration" msgid="5688706061127375131">"− <xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Redémarrer la session"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Appuyer pour lancer une nouvelle session de démonstration"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Lancement de la démo…"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Redémarrage de la session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Rétablir la configuration d\'usine pour utiliser cet appareil sans restrictions"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Appuyez ici pour en savoir plus."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 0626546..12c3c17 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
     <string name="app_info" msgid="6856026610594615344">"Información da aplicación"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sesión"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toca para iniciar unha nova sesión de demostración"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Iniciando demostración"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reiniciando sesión"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Restablecemento dos valores de fábrica para usar este dispositivo sen restricións"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toca para acceder a máis información"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index f9dee58ff2..0fd5699 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -876,20 +876,20 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>વ</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>મિ માં</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>મિ માં</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>મિ. માં</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>મિ. માં</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ક માં</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ક માં</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ક. માં</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ક. માં</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>દિ માં</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>દિ માં</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>દિ. માં</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>દિ. માં</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>વ માં</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>વ માં</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>વ. માં</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>વ. માં</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> મિનિટ પહેલાં</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"અનપિન કરો"</string>
     <string name="app_info" msgid="6856026610594615344">"ઍપ્લિકેશન માહિતી"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"સત્ર પુનઃપ્રારંભ કરો"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"નવું ડેમો સત્ર પ્રારંભ કરવા માટે ટૅપ કરો"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ડેમો પુનઃપ્રારંભ કરી રહ્યાં છે"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"સત્ર પુનઃપ્રારંભ કરી રહ્યાં છે"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"આ ઉપકરણનો પ્રતિબંધો વિના ઉપયોગ કરવા માટે ફેક્ટરી રીસેટ કરો"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"વધુ જાણવા માટે ટચ કરો."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> અક્ષમ કર્યું"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 4b0664f..4c8ec79 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -860,12 +860,12 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"अभी"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> मि</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मि</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> मि.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मि.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> घं</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घं</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> घं.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घं.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> दिन</item>
@@ -876,12 +876,12 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> वर्ष</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> मि में</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मि में</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> मिनट में</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मिनट में</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> घं में</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घं में</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> घंटे में</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घंटे में</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> दिन में</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन करें"</string>
     <string name="app_info" msgid="6856026610594615344">"ऐप की जानकारी"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"सत्र पुन: प्रारंभ करें"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"एक नया डेमो सत्र प्रारंभ करने के लिए टैप करें"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"डेमो प्रारंभ हो रहा है"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"सत्र पुन: प्रारंभ हो रहा है"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"इस डिवाइस को प्रतिबंधों के बिना उपयोग करने के लिए फ़ैक्टरी रीसेट करें"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जानने के लिए स्पर्श करें."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 766d10b..d1752c6 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1685,6 +1685,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Otkvači"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacije o aplikaciji"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Ponovno pokretanje sesije"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Dodirnite za pokretanje nove demo-sesije"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Pokretanje demonstracije"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Ponovno pokretanje sesije"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Uređaj je vraćen na tvorničke postavke da biste ga mogli upotrebljavati bez ograničenja"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dodirnite da biste saznali više."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 5609b1f..73dc3c7 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Feloldás"</string>
     <string name="app_info" msgid="6856026610594615344">"Alkalmazásinformáció"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Munkamenet újraindítása"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Koppintson az új, bemutató munkamenet indításához"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Bemutató indítása"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Munkamenet újraindítása"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Állítsa vissza a gyári beállításokat az eszköz korlátozások nélküli használata érdekében"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Érintse meg a további információkért."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 993cd7e..8d78cf5 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1610,7 +1610,7 @@
     <string name="stk_cc_ss_to_ss" msgid="5470768854991452695">"SS հարցումը փոխվել է նոր SS հարցման:"</string>
     <string name="notification_work_profile_content_description" msgid="4600554564103770764">"Աշխատանքային պրոֆիլ"</string>
     <string name="expand_button_content_description" msgid="5855955413376384681">"«Ընդարձակել» կոճակ"</string>
-    <string name="expand_action_accessibility" msgid="5307730695723718254">"Կոծկել/Ընդարձակել"</string>
+    <string name="expand_action_accessibility" msgid="5307730695723718254">"փոխարկել ընդլայնումը"</string>
     <string name="usb_midi_peripheral_name" msgid="7221113987741003817">"Android USB արտաքին միացք"</string>
     <string name="usb_midi_peripheral_manufacturer_name" msgid="7176526170008970168">"Android"</string>
     <string name="usb_midi_peripheral_product_name" msgid="4971827859165280403">"USB արտաքին միացք"</string>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Ապամրացնել"</string>
     <string name="app_info" msgid="6856026610594615344">"Հավելվածի տվյալներ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Վերագործարկել աշխատաշրջանը"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Հպեք՝ նոր ցուցադրական աշխատաշրջան սկսելու համար"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Ցուցադրական օգտվողի գործարկում"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Աշխատաշրջանի վերագործարկում"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Սարքն առանց սահմանափակումների օգտագործելու համար կատարեք գործարանային վերակայում"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Հպեք՝ ավելին իմանալու համար:"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Անջատած <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index da0afc8..74efb2d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Lepas pin"</string>
     <string name="app_info" msgid="6856026610594615344">"Info aplikasi"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Mulai Ulang Sesi"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Ketuk untuk memulai sesi demo baru"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Memulai demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Memulai ulang sesi"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Dikembalikan ke setelan pabrik agar perangkat ini dapat digunakan tanpa batasan"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Sentuh untuk mempelajari lebih lanjut."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 661f5b5..8e09f40 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -858,34 +858,34 @@
       <item quantity="one"><xliff:g id="COUNT">%d</xliff:g> klukkustund</item>
       <item quantity="other"><xliff:g id="COUNT">%d</xliff:g> klukkustundir</item>
     </plurals>
-    <string name="now_string_shortest" msgid="8912796667087856402">"nú"</string>
+    <string name="now_string_shortest" msgid="8912796667087856402">"núna"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> m.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m.</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> mín.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> mín.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> k.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> k.</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> klst.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> klst.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> d.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d.</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> á.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> á.</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ár</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ár</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> m.</item>
-      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> m.</item>
+      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> mín.</item>
+      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> mín.</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> k.</item>
-      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> k.</item>
+      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> klst.</item>
+      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> klst.</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> d.</item>
-      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> d.</item>
+      <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="other">eftir <xliff:g id="COUNT_1">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
       <item quantity="one">eftir <xliff:g id="COUNT_1">%d</xliff:g> ár</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Losa"</string>
     <string name="app_info" msgid="6856026610594615344">"Forritsupplýsingar"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Endurræsa lotu"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Ýttu til að hefja nýja tilraunalotu"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Byrjar kynningu"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Endurræsir lotu"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Núllstilltu til að nota þetta tæki án takmarkana"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Snertu til að fá frekari upplýsingar."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index d32e959..8318d45 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Sblocca"</string>
     <string name="app_info" msgid="6856026610594615344">"Informazioni app"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Riavvia la sessione"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tocca per iniziare una nuova sessione demo"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Avvio della demo in corso"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Riavvio della sessione in corso"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Esegui il ripristino dei dati di fabbrica per utilizzare il dispositivo senza limitazioni"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tocca per ulteriori informazioni."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 254bba9..c1f5246 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"בטל הצמדה"</string>
     <string name="app_info" msgid="6856026610594615344">"פרטי אפליקציה"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"הפעלה מחדש"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"הקש כדי להפעיל הדגמה חדשה"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"מתחיל בהדגמה"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"מפעיל מחדש"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"איפוס להגדרות היצרן כדי לאפשר שימוש במכשיר ללא מגבלות"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"גע לקבלת מידע נוסף."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> הושבת"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index c7529b7..99e88d1 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"固定を解除"</string>
     <string name="app_info" msgid="6856026610594615344">"アプリ情報"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"新しいセッションの開始"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"新しいデモセッションを開始するにはタップ"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"デモを開始しています"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"新しいセッションを開始しています"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"制限なしでこの端末を使用するには初期状態にリセットしてください"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"タップして詳細をご確認ください。"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"停止済みの「<xliff:g id="LABEL">%1$s</xliff:g>」"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 5f5ded9..0c7c42d 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ჩამაგრების მოხსნა"</string>
     <string name="app_info" msgid="6856026610594615344">"აპის შესახებ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"სესიის ხელახლა დაწყება"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"შეეხეთ ახალი სადემონსტრაციო სესიის დასაწყებად"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"მიმდინარეობს დემონსტრაციის დაწყება"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"მიმდინარეობს სესიის ხელახლა დაწყება"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ამ მოწყობილობის შეზღუდვების გარეშე გამოსაყენებლად, დააბრუნეთ ქარხნული პარამეტრები"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"შეეხეთ მეტის გასაგებად."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"გათიშული <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index c5c19c8..d635365 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"қазір"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>м</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>м</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> м.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> м.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>с</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>с</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> с.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> с.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>к</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>к</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> к.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> к.</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ж</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ж</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ж.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ж.</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>м</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>м</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> м.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> м.</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>с</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>с</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> с.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> с.</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>к</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>к</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> к.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> к.</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ж</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ж</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ж.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ж.</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> минут бұрын</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Босату"</string>
     <string name="app_info" msgid="6856026610594615344">"Қолданба ақпараты"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Сеансты қайта бастау"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Жаңа демо сеансты бастау үшін түртіңіз"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Демоны бастау"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Сеансты қайта бастау"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Осы құрылғыны шектеусіз пайдалану үшін зауыттық параметрлерді қалпына келтіріңіз"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Қосымша мәліметтер алу үшін түртіңіз."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өшірулі"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 36ed267..aa7b35a 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -1651,6 +1651,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"មិនខ្ទាស់"</string>
     <string name="app_info" msgid="6856026610594615344">"ព័ត៌មាន​កម្មវិធី"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"ចាប់ផ្តើមវេនម្តងទៀត"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"ប៉ះដើម្បីចាប់ផ្តើមវេនបង្ហាញសាកល្បងថ្មី"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"កំពុងចាប់ផ្តើមការបង្ហាញសាកល្បង"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"ចាប់ផ្តើមវេនសារជាថ្មី"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"កំណត់ដូចចេញពីរោងចក្រឡើងវិញដើម្បីប្រើឧបករណ៍នេះដោយគ្មានការរឹតបន្តឹង"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ប៉ះ​ ដើម្បី​​ស្វែងយល់​បន្ថែម។"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ដែលបានបិទដំណើរការ"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index b898e14..9967daf 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -876,20 +876,20 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ವ</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ನಿ.ದಲ್ಲಿ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ನಿ.ದಲ್ಲಿ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ನಿ ನಲ್ಲಿ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ನಿ ನಲ್ಲಿ</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ಗಂ.ಯಲ್ಲಿ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ಗಂ.ಯಲ್ಲಿ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ಗಂ ನಲ್ಲಿ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ಗಂ ನಲ್ಲಿ</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ದಿ.ದಲ್ಲಿ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ದಿ.ದಲ್ಲಿ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ದಿ ನಲ್ಲಿ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ದಿ ನಲ್ಲಿ</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ವ.ದಲ್ಲಿ</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ವ.ದಲ್ಲಿ</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>ವ ನಲ್ಲಿ</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ವ ನಲ್ಲಿ</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> ನಿಮಿಷಗಳ ಹಿಂದೆ</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ಅನ್‌ಪಿನ್"</string>
     <string name="app_info" msgid="6856026610594615344">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"ಸೆಶನ್ ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"ಹೊಸ ಡೆಮೊ ಸೆಶನ್ ಪ್ರಾರಂಭಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ಡೆಮೋ ಪ್ರಾರಂಭವಾಗುತ್ತಿದೆ"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"ಸೆಶನ್ ಮರುಪ್ರಾರಂಭಿಸಲಾಗುತ್ತಿದೆ"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ನಿರ್ಬಂಧಗಳು ಇಲ್ಲದೆಯೇ ಈ ಸಾಧನವನ್ನು ಬಳಸಲು ಫ್ಯಾಕ್ಟರಿ ಮರುಹೊಂದಿಸಿ"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಸ್ಪರ್ಶಿಸಿ."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 8a4dbc9..1c165f9 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"고정 해제"</string>
     <string name="app_info" msgid="6856026610594615344">"앱 정보"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"세션 다시 시작"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"탭하여 새로운 데모 세션 시작"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"데모 시작 중"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"세션 다시 시작 중"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"제한 없이 기기를 사용하기 위한 초기화"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"자세한 내용을 보려면 터치하세요."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> 사용 중지됨"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 3ffc2b7..1af24dd 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -545,7 +545,7 @@
     <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Экрн клпснн айрм функцялрн өчр"</string>
     <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Экранды кулпулоо функцияларынын айрымдарын колдонууга тыюу салуу"</string>
   <string-array name="phoneTypes">
-    <item msgid="8901098336658710359">"Үй"</item>
+    <item msgid="8901098336658710359">"Башкы бет"</item>
     <item msgid="869923650527136615">"Мобилдик"</item>
     <item msgid="7897544654242874543">"Жумуш"</item>
     <item msgid="1103601433382158155">"Жумуш факсы"</item>
@@ -555,19 +555,19 @@
     <item msgid="9192514806975898961">"Өзгөчө"</item>
   </string-array>
   <string-array name="emailAddressTypes">
-    <item msgid="8073994352956129127">"Үй"</item>
+    <item msgid="8073994352956129127">"Башкы бет"</item>
     <item msgid="7084237356602625604">"Жумуш"</item>
     <item msgid="1112044410659011023">"Башка"</item>
     <item msgid="2374913952870110618">"Өзгөчө"</item>
   </string-array>
   <string-array name="postalAddressTypes">
-    <item msgid="6880257626740047286">"Үй"</item>
+    <item msgid="6880257626740047286">"Башкы бет"</item>
     <item msgid="5629153956045109251">"Жумуш"</item>
     <item msgid="4966604264500343469">"Башка"</item>
     <item msgid="4932682847595299369">"Өзгөчө"</item>
   </string-array>
   <string-array name="imAddressTypes">
-    <item msgid="1738585194601476694">"Үй"</item>
+    <item msgid="1738585194601476694">"Башкы бет"</item>
     <item msgid="1359644565647383708">"Жумуш"</item>
     <item msgid="7868549401053615677">"Башка"</item>
     <item msgid="3145118944639869809">"Өзгөчө"</item>
@@ -588,7 +588,7 @@
     <item msgid="1648797903785279353">"Jabber"</item>
   </string-array>
     <string name="phoneTypeCustom" msgid="1644738059053355820">"Өзгөчө"</string>
-    <string name="phoneTypeHome" msgid="2570923463033985887">"Үй"</string>
+    <string name="phoneTypeHome" msgid="2570923463033985887">"Башкы бет"</string>
     <string name="phoneTypeMobile" msgid="6501463557754751037">"Мобилдик"</string>
     <string name="phoneTypeWork" msgid="8863939667059911633">"Жумуш"</string>
     <string name="phoneTypeFaxWork" msgid="3517792160008890912">"Жумуш факсы"</string>
@@ -613,16 +613,16 @@
     <string name="eventTypeAnniversary" msgid="3876779744518284000">"Маараке"</string>
     <string name="eventTypeOther" msgid="7388178939010143077">"Башка"</string>
     <string name="emailTypeCustom" msgid="8525960257804213846">"Өзгөчө"</string>
-    <string name="emailTypeHome" msgid="449227236140433919">"Жеке"</string>
+    <string name="emailTypeHome" msgid="449227236140433919">"Башкы бет"</string>
     <string name="emailTypeWork" msgid="3548058059601149973">"Жумуш"</string>
     <string name="emailTypeOther" msgid="2923008695272639549">"Башка"</string>
     <string name="emailTypeMobile" msgid="119919005321166205">"Мобилдик"</string>
     <string name="postalTypeCustom" msgid="8903206903060479902">"Өзгөчө"</string>
-    <string name="postalTypeHome" msgid="8165756977184483097">"Үй"</string>
+    <string name="postalTypeHome" msgid="8165756977184483097">"Башкы бет"</string>
     <string name="postalTypeWork" msgid="5268172772387694495">"Жумуш"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Башка"</string>
     <string name="imTypeCustom" msgid="2074028755527826046">"Өзгөчө"</string>
-    <string name="imTypeHome" msgid="6241181032954263892">"Үй"</string>
+    <string name="imTypeHome" msgid="6241181032954263892">"Башкы бет"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Жумуш"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Башка"</string>
     <string name="imProtocolCustom" msgid="6919453836618749992">"Өзгөчө"</string>
@@ -654,7 +654,7 @@
     <string name="relationTypeSister" msgid="1735983554479076481">"Эже-сиңди"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Жубай"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Өзгөчө"</string>
-    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Үй"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Башкы бет"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Жумуш"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Башка"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Байланышты көрсөтүүчү эч бир колдонмо жок."</string>
@@ -860,24 +860,24 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"азыр"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>мүн.</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>мүн.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> мүн.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> мүн.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>с.</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>с.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> с.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> с.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>к.</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>к.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> к.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> к.</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ж.</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ж.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ж.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ж.</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>мүн. кийин</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>мүн. кийин</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> мүн. кийин</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> мүн. кийин</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> с. кийин</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Кадоодон алып коюу"</string>
     <string name="app_info" msgid="6856026610594615344">"Колдонмо тууралуу"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Сеансты кайра баштоо"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Жаңы демо сеансын баштоо үчүн таптап коюңуз"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Демо башталууда"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Сеанс кайра башталууда"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Бул түзмөктү чектөөсүз колдонуу үчүн аны баштапкы абалга келтириңиз"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Көбүрөөк билүү үчүн тийип коюңуз."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өчүрүлдү"</string>
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index 6fda52a..b003764 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ຖອນປັກໝຸດ"</string>
     <string name="app_info" msgid="6856026610594615344">"ຂໍ້ມູນແອັບ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"ເລີ່ມເຊດຊັນຄືນໃໝ່"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"ແຕະເພື່ອເລີ່ມເຊດຊັນເດໂມໃໝ່"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ກຳລັງເລີ່ມເດໂມ"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"ເລີ່ມເຊດຊັນໃໝ່"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ຣີເຊັດໃຫ້ເປັນຄ່າໂຮງງານເພື່ອໃຊ້ອຸປະກອນນີ້ໂດຍບໍ່ມີຂໍ້ຈຳກັດ"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ແຕະເພື່ອສຶກສາເພີ່ມເຕີມ."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ປິດການນຳໃຊ້ <xliff:g id="LABEL">%1$s</xliff:g> ແລ້ວ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0b062d1..8bd85b2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -874,16 +874,16 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"dabar"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>min</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
+      <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> val.</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> val.</item>
       <item quantity="many"><xliff:g id="COUNT_1">%d</xliff:g> val.</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> val.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> d.</item>
@@ -898,16 +898,16 @@
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m.</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">po <xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="few">po <xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="many">po <xliff:g id="COUNT_1">%d</xliff:g>min</item>
-      <item quantity="other">po <xliff:g id="COUNT_1">%d</xliff:g>min</item>
+      <item quantity="one">po <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="few">po <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="many">po <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="other">po <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">po <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="few">po <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="many">po <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="other">po <xliff:g id="COUNT_1">%d</xliff:g>h</item>
+      <item quantity="one">po <xliff:g id="COUNT_1">%d</xliff:g> val.</item>
+      <item quantity="few">po <xliff:g id="COUNT_1">%d</xliff:g> val.</item>
+      <item quantity="many">po <xliff:g id="COUNT_1">%d</xliff:g> val.</item>
+      <item quantity="other">po <xliff:g id="COUNT_1">%d</xliff:g> val.</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
       <item quantity="one">po <xliff:g id="COUNT_1">%d</xliff:g> d.</item>
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Atsegti"</string>
     <string name="app_info" msgid="6856026610594615344">"Programos informacija"</string>
     <string name="negative_duration" msgid="5688706061127375131">"–<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Paleisti sesiją iš naujo"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Palieskite, kad pradėtumėte naują demonstracinės versijos sesiją"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Paleidžiama demonstracinė versija"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Seansas paleidžiamas iš naujo"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Atkurkite gamyklinius nustatymus, kad galėtumėte naudoti šį įrenginį be apribojimų"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Palieskite, kad sužinotumėte daugiau."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 47f1f26..5b91848 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1685,6 +1685,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Atspraust"</string>
     <string name="app_info" msgid="6856026610594615344">"Lietotnes informācija"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Atkārtoti palaidiet sesiju"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Pieskarieties, lai sāktu jaunu demonstrācijas sesiju."</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demonstrācijas startēšana"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sesijas restartēšana"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Rūpnīcas datu atiestatīšana ierīces neierobežotai izmantošanai"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pieskarieties, lai uzzinātu vairāk."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 845a42d..010958f 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -1654,6 +1654,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Откачете"</string>
     <string name="app_info" msgid="6856026610594615344">"Информации за апликација"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Започнете сесија одново"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Допрете за да започнете нова демо сесија"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Демото стартува"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Сесијата се рестартира"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетирајте до фабричките поставки за уредов да го користите без ограничувања"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Допрете за да дознаете повеќе."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Оневозможен <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 7b18d91..7120cad 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"അൺപിൻ ചെയ്യുക"</string>
     <string name="app_info" msgid="6856026610594615344">"ആപ്പ് വിവരം"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"സെഷൻ പുനരാരംഭിക്കുക"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"പുതിയൊരു ഡെമോ സെഷൻ ആരംഭിക്കാൻ ടാപ്പുചെയ്യുക"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ഡെമോ ആരംഭിക്കുന്നു"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"സെഷൻ പുനരാരംഭിക്കുന്നു"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"നിയന്ത്രണങ്ങൾ ഇല്ലാതെ ഈ ഉപകരണം ഉപയോഗിക്കാൻ ഫാക്ടറി റീസെറ്റ് നടത്തുക"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"കൂടുതലറിയുന്നതിന് സ്‌പർശിക്കുക."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index baf95b1..71c09dc 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -860,12 +860,12 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"одоо"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>мин</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>мин</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>минут</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>минут</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ц</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ц</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>цаг</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>цаг</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>хоног</item>
@@ -876,19 +876,19 @@
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>жил</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>мин</item>
-      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>мин</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>минутад</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>минутад</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>цаг</item>
-      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>цаг</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>цагт</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>цагт</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
       <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>хоногт</item>
-      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>хоног</item>
+      <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>хоногт</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>жил</item>
+      <item quantity="other"> <xliff:g id="COUNT_1">%d</xliff:g>жилд</item>
       <item quantity="one"> <xliff:g id="COUNT_0">%d</xliff:g>жилд</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
@@ -1647,6 +1647,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"Апп-н мэдээлэл"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Харилцан үйлдлийг дахин эхлүүлэх"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Демо харилцан үйлдлийг шинээр эхлүүлэхийн тулд товшино уу"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Жишээг эхлүүлж байна"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Харилцан үйлдлийг дахин эхлүүлж байна"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Энэ төхөөрөмжийг хязгаарлалтгүй ашиглахын тулд үйлдвэрийн тохиргоонд дахин тохируулна уу"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Дэлгэрэнгүй үзэх бол дарна уу."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>-г цуцалсан"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index e2d11c8..0ee3203 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन करा"</string>
     <string name="app_info" msgid="6856026610594615344">"अॅप माहिती"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"सत्र पुन्हा सुरू करा"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"नवीन डेमो सत्र प्रारंभ करण्यासाठी टॅप करा"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"डेमो प्रारंभ करत आहे"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"सत्र पुन्हा सुरू करणे"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"हे डिव्हाइस निर्बंधांशिवाय वापरण्यासाठी फॅक्टरी रीसेट करा"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"अधिक जाणून घेण्यासाठी स्पर्श करा."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> अक्षम केले"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index 8945524..e48d7d6 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Nyahsemat"</string>
     <string name="app_info" msgid="6856026610594615344">"Maklumat apl"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Mulakan Semula Sesi"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Ketik untuk memulakan sesi tunjuk cara baharu"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Memulakan tunjuk cara"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Memulakan semula sesi"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Lakukan tetapan semula kilang untuk menggunakan peranti ini tanpa sekatan"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ketik untuk mengetahui lebih lanjut."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 76ac215..72fc86e 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ဖြုတ်ပါ"</string>
     <string name="app_info" msgid="6856026610594615344">"အက်ပ်အချက်အလက်"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"စက်ရှင်ကို ပြန်စပါ"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"သရုပ်ပြစက်ရှင်အသစ်စတင်ရန် တို့ပါ"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"သရုပ်ပြချက်ကို စတင်နေသည်"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"စက်ရှင်ကို ပြန်လည်စတင်နေပါသည်"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ဤစက်ပစ္စည်းကို ကန့်သတ်ချက်များမပါဘဲ အသုံးပြုရန် စက်ရုံထုတ်ဆက်တင်အတိုင်း ပြန်လည်သတ်မှတ်ပါ"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ပိုမိုလေ့လာရန် တို့ပါ။"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ပိတ်ထားသည့် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ee3c606..20de4a6 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1618,7 +1618,8 @@
     <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"Lukk overflytsmenyen"</string>
     <string name="maximize_button_text" msgid="7543285286182446254">"Maksimer"</string>
     <string name="close_button_text" msgid="3937902162644062866">"Lukk"</string>
-    <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g><xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
+    <!-- no translation found for notification_messaging_title_template (3452480118762691020) -->
+    <skip />
     <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> er valgt</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> er valgt</item>
@@ -1649,6 +1650,12 @@
     <string name="unpin_target" msgid="3556545602439143442">"Løsne"</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Start økten på nytt"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Trykk for å starte en ny demoøkt"</string>
+    <!-- no translation found for demo_starting_message (7574017688324606624) -->
+    <skip />
+    <!-- no translation found for demo_restarting_message (1363894248779727028) -->
+    <skip />
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Tilbakestill til fabrikkstandard for å bruke denne enheten uten begrensninger"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Trykk for å finne ut mer."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 1ea7dbf..79d9ba8 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"अहिले"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>मिनेट</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मिनेट</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> मिनेट</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>घन्टा</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घन्टा</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> घन्टा</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>दिन</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> दिन</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> दिन</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>वर्ष</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> वर्ष</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> वर्ष</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>मिनेटमा</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>मिनेटमा</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मिनेटमा</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> मिनेटमा</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> घन्टामा</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>घन्टामा</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> घन्टामा</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>दिनमा</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>दिनमा</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> दिनमा</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> दिनमा</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>वर्षमा</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>वर्षमा</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> वर्षमा</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> वर्षमा</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> मिनेट अघि</item>
@@ -1655,6 +1655,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"अनपिन गर्नुहोस्"</string>
     <string name="app_info" msgid="6856026610594615344">"अनुप्रयोगका बारे जानकारी"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"सत्रलाई पुन:सुरु गर्नुहोस्"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"एउटा नयाँ डेमो सम्बन्धी सत्र सुरु गर्न ट्याप गर्नुहोस्"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"डेमो सुरु गर्दै"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"सत्रलाई पुन:सुरु गर्दै"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"यस यन्त्रलाई सीमितताहरू बिना प्रयोग गर्नका लागि फ्याक्ट्री रिसेट गर्नुहोस्"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"थप जान्नका लागि छुनुहोस्।"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> लाई असक्षम गरियो"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index c3eee67..9f9a07b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"nu"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>m</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>u</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>u</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> u</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> u</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>d</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>j</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>j</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> j</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> j</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g>m</item>
+      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g> m</item>
+      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g> m</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g>u</item>
-      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g>u</item>
+      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g> u</item>
+      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g> u</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g>d</item>
+      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g> d</item>
+      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g> d</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g>j</item>
-      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g>j</item>
+      <item quantity="other">over <xliff:g id="COUNT_1">%d</xliff:g> j</item>
+      <item quantity="one">over <xliff:g id="COUNT_0">%d</xliff:g> j</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> minuten geleden</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Losmaken"</string>
     <string name="app_info" msgid="6856026610594615344">"App-info"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Sessie opnieuw starten"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tik om een nieuwe demosessie te starten"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo starten"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sessie opnieuw starten"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Zet dit apparaat terug op de fabrieksinstellingen om het zonder beperkingen te gebruiken"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tik voor meer informatie."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
diff --git a/core/res/res/values-notround/dimens_micro.xml b/core/res/res/values-notround/dimens_micro.xml
new file mode 100644
index 0000000..51291d9
--- /dev/null
+++ b/core/res/res/values-notround/dimens_micro.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <dimen name="dialog_padding_micro">8dp</dimen>
+    <dimen name="list_item_padding_left_micro">16dp</dimen>
+    <dimen name="list_item_padding_right_micro">16dp</dimen>
+</resources>
diff --git a/core/res/res/values-notround/styles_micro.xml b/core/res/res/values-notround/styles_micro.xml
new file mode 100644
index 0000000..1294660
--- /dev/null
+++ b/core/res/res/values-notround/styles_micro.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources>
+    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small">
+        <item name="textAlignment">viewStart</item>
+    </style>
+    <style name="PreferenceFragment.Micro" parent="PreferenceFragment.Material"/>
+    <style name="PreferenceFragmentList.Micro" parent="PreferenceFragmentList.Material"/>
+</resources>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 12f2ba7..6cc7c30 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ਅਨਪਿੰਨ ਕਰੋ"</string>
     <string name="app_info" msgid="6856026610594615344">"ਐਪ ਜਾਣਕਾਰੀ"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"ਸੈਸ਼ਨ ਦੁਬਾਰਾ ਸ਼ੁਰੂ ਕਰੋ"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"ਇੱਕ ਨਵਾਂ ਡੈਮੋ ਸੈਸ਼ਨ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ਡੈਮੋ ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"ਸੈਸ਼ਨ ਮੁੜ-ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ਇਸ ਡੀਵਾਈਸ ਨੂੰ ਬਿਨਾਂ ਪਾਬੰਦੀਆਂ ਦੇ ਵਰਤਣ ਲਈ ਫੈਕਟਰੀ ਰੀਸੈੱਟ ਕਰੋ"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"ਹੋਰ ਜਾਣਨ ਲਈ ਸਪਰਸ਼ ਕਰੋ।"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 2291d037..680e53d 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Odepnij"</string>
     <string name="app_info" msgid="6856026610594615344">"O aplikacji"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Ponowne rozpoczęcie sesji"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Kliknij, by rozpocząć nową sesję demonstracyjną"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Rozpoczynam demonstrację"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Uruchamiam ponownie sesję"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Aby używać tego urządzenia bez ograniczeń, przywróć ustawienia fabryczne"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Kliknij, by dowiedzieć się więcej."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 6907a6c..18c6d3e 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sessão"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toque para iniciar uma nova sessão de demonstração"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Iniciando demonstração"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reiniciando sessão"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index fe136c3..b5d87f7 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Soltar"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações da aplicação"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sessão"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toque para iniciar uma nova sessão de demonstração"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"A iniciar a demonstração"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"A reiniciar a sessão"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Repor os dados de fábrica para utilizar o dispositivo sem restrições"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 6907a6c..18c6d3e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Liberar guia"</string>
     <string name="app_info" msgid="6856026610594615344">"Informações do app"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reiniciar sessão"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Toque para iniciar uma nova sessão de demonstração"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Iniciando demonstração"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reiniciando sessão"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Redefinir para a configuração original para usar este dispositivo sem restrições"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Toque para saber mais."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index fe19d39..947bb1a 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -20,7 +20,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="byteShort" msgid="8340973892742019101">"O"</string>
     <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
@@ -867,9 +867,9 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"acum"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> h</item>
@@ -878,33 +878,33 @@
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> zile</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> zile</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> de zile</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> zi</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
       <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> ani</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ani</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> de ani</item>
       <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> an</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="few">în <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="other">în <xliff:g id="COUNT_1">%d</xliff:g> min</item>
-      <item quantity="one">în <xliff:g id="COUNT_0">%d</xliff:g> min.</item>
+      <item quantity="few">peste <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="other">peste <xliff:g id="COUNT_1">%d</xliff:g> min.</item>
+      <item quantity="one">peste <xliff:g id="COUNT_0">%d</xliff:g> min.</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="few">în <xliff:g id="COUNT_1">%d</xliff:g> h</item>
-      <item quantity="other">în <xliff:g id="COUNT_1">%d</xliff:g> h</item>
-      <item quantity="one">în <xliff:g id="COUNT_0">%d</xliff:g> h</item>
+      <item quantity="few">peste <xliff:g id="COUNT_1">%d</xliff:g> h</item>
+      <item quantity="other">peste <xliff:g id="COUNT_1">%d</xliff:g> h</item>
+      <item quantity="one">peste <xliff:g id="COUNT_0">%d</xliff:g> h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="few">în <xliff:g id="COUNT_1">%d</xliff:g> zile</item>
-      <item quantity="other">în <xliff:g id="COUNT_1">%d</xliff:g> zile</item>
-      <item quantity="one">în <xliff:g id="COUNT_0">%d</xliff:g> zi</item>
+      <item quantity="few">peste <xliff:g id="COUNT_1">%d</xliff:g> zile</item>
+      <item quantity="other">peste <xliff:g id="COUNT_1">%d</xliff:g> de zile</item>
+      <item quantity="one">peste <xliff:g id="COUNT_0">%d</xliff:g> zi</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="few">în <xliff:g id="COUNT_1">%d</xliff:g> ani</item>
-      <item quantity="other">în <xliff:g id="COUNT_1">%d</xliff:g> ani</item>
-      <item quantity="one">în <xliff:g id="COUNT_0">%d</xliff:g> an</item>
+      <item quantity="few">peste <xliff:g id="COUNT_1">%d</xliff:g> ani</item>
+      <item quantity="other">peste <xliff:g id="COUNT_1">%d</xliff:g> de ani</item>
+      <item quantity="one">peste <xliff:g id="COUNT_0">%d</xliff:g> an</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="few">acum <xliff:g id="COUNT_1">%d</xliff:g> minute</item>
@@ -1685,6 +1685,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Anulați fixarea"</string>
     <string name="app_info" msgid="6856026610594615344">"Informații despre aplicație"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reporniți sesiunea"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Atingeți pentru a începe o nouă sesiune demonstrativă"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Se pornește versiunea demonstrativă"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Se repornește sesiunea"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Reveniți la setările din fabrică pentru a folosi acest dispozitiv fără restricții"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Atingeți pentru a afla mai multe."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-round/dimens_micro.xml
new file mode 100644
index 0000000..8dbc905
--- /dev/null
+++ b/core/res/res/values-round/dimens_micro.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <dimen name="dialog_padding_micro">32dp</dimen>
+    <dimen name="list_item_padding_left_micro">40dp</dimen>
+    <dimen name="list_item_padding_right_micro">24dp</dimen>
+</resources>
diff --git a/core/res/res/values-round/styles_micro.xml b/core/res/res/values-round/styles_micro.xml
new file mode 100644
index 0000000..f19adde
--- /dev/null
+++ b/core/res/res/values-round/styles_micro.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<resources>
+    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small">
+        <item name="textAlignment">center</item>
+    </style>
+    <style name="PreferenceFragment.Micro" parent="PreferenceFragment.Material">
+        <item name="paddingTop">22dp</item>
+        <item name="paddingBottom">22dp</item>
+        <item name="clipToPadding">false</item>
+    </style>
+    <style name="PreferenceFragmentList.Micro" parent="PreferenceFragmentList.Material">
+        <item name="paddingTop">22dp</item>
+        <item name="paddingBottom">22dp</item>
+    </style>
+</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e885d70..16c5752 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Открепить"</string>
     <string name="app_info" msgid="6856026610594615344">"О приложении"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Начните сеанс заново"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Нажмите, чтобы начать новый демосеанс."</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Запуск деморежима"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Повтор сеанса"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Сброс до заводских настроек для работы без ограничений"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Нажмите, чтобы узнать больше."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виджет <xliff:g id="LABEL">%1$s</xliff:g> отключен"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index 5626d47d..b406c34 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -862,36 +862,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"දැන්"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="one">මි<xliff:g id="COUNT_1">%d</xliff:g></item>
-      <item quantity="other">මි<xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="one">මි <xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="other">මි <xliff:g id="COUNT_1">%d</xliff:g></item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="one">පැ<xliff:g id="COUNT_1">%d</xliff:g></item>
-      <item quantity="other">පැ<xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="one">පැ <xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="other">පැ <xliff:g id="COUNT_1">%d</xliff:g></item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="one">දි <xliff:g id="COUNT_1">%d</xliff:g></item>
-      <item quantity="other">දි<xliff:g id="COUNT_1">%d</xliff:g></item>
+      <item quantity="other">දි <xliff:g id="COUNT_1">%d</xliff:g></item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
       <item quantity="one">ව <xliff:g id="COUNT_1">%d</xliff:g></item>
       <item quantity="other">ව <xliff:g id="COUNT_1">%d</xliff:g></item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="one">මි<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
-      <item quantity="other">මි<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="one">මි <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="other">මි <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="one">පැ<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
-      <item quantity="other">පැ<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="one">පැ <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="other">පැ <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="one">දි<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
-      <item quantity="other">දි<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="one">දි <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="other">දි <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="one">ව<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
-      <item quantity="other">ව<xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="one">ව <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
+      <item quantity="other">ව <xliff:g id="COUNT_1">%d</xliff:g>කදී</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="one">මිනිත්තු <xliff:g id="COUNT_1">%d</xliff:g>කට පෙර</item>
@@ -1651,6 +1651,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"ගලවන්න"</string>
     <string name="app_info" msgid="6856026610594615344">"යෙදුම් තොරතුරු"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"සැසිය ආරම්භ කරන්න"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"නව ආදර්ශ සැසියක් ආරම්භ කිරීම තට්ටු කරන්න"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ආදර්ශනය ආරම්භ කරමින්"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"සැසිය නැවත ආරම්භ කරමින්"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"සීමා කිරීම්වලින් තොරව මෙම උපාංගය භාවිත කිරීමට කර්මාන්ත ශාලා යළි සැකසීම"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"තව දැන ගැනීමට ස්පර්ශ කරන්න."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"අබල කළ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 54337ba..89d762c 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Uvoľniť"</string>
     <string name="app_info" msgid="6856026610594615344">"Info o aplikácii"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Reštartujte reláciu"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Klepnutím začnete novú demo reláciu"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Spúšťa sa ukážka"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Reštartuje sa relácia"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Ak chcete toto zariadenie používať bez obmedzení, obnovte na ňom továrenské nastavenia"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Klepnutím získate ďalšie informácie."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index f13d1aa..bc7637f 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -561,7 +561,7 @@
     <item msgid="9192514806975898961">"Po meri"</item>
   </string-array>
   <string-array name="emailAddressTypes">
-    <item msgid="8073994352956129127">"Dom"</item>
+    <item msgid="8073994352956129127">"Doma"</item>
     <item msgid="7084237356602625604">"Služba"</item>
     <item msgid="1112044410659011023">"Drugo"</item>
     <item msgid="2374913952870110618">"Po meri"</item>
@@ -573,7 +573,7 @@
     <item msgid="4932682847595299369">"Po meri"</item>
   </string-array>
   <string-array name="imAddressTypes">
-    <item msgid="1738585194601476694">"Dom"</item>
+    <item msgid="1738585194601476694">"Začetna stran"</item>
     <item msgid="1359644565647383708">"Služba"</item>
     <item msgid="7868549401053615677">"Drugo"</item>
     <item msgid="3145118944639869809">"Po meri"</item>
@@ -628,7 +628,7 @@
     <string name="postalTypeWork" msgid="5268172772387694495">"Služba"</string>
     <string name="postalTypeOther" msgid="2726111966623584341">"Drugo"</string>
     <string name="imTypeCustom" msgid="2074028755527826046">"Po meri"</string>
-    <string name="imTypeHome" msgid="6241181032954263892">"Dom"</string>
+    <string name="imTypeHome" msgid="6241181032954263892">"Začetna stran"</string>
     <string name="imTypeWork" msgid="1371489290242433090">"Služba"</string>
     <string name="imTypeOther" msgid="5377007495735915478">"Drugo"</string>
     <string name="imProtocolCustom" msgid="6919453836618749992">"Po meri"</string>
@@ -660,7 +660,7 @@
     <string name="relationTypeSister" msgid="1735983554479076481">"Sestra"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"Zakonski partner"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"Po meri"</string>
-    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Dom"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"Domov"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"Služba"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"Drugo"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"Ni aplikacije za ogled tega stika."</string>
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Odpenjanje"</string>
     <string name="app_info" msgid="6856026610594615344">"Podatki o aplikaciji"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Vnovični zagon seje"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Dotaknite se, če želite začeti novo predstavitveno sejo"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Začenjanje predstavitve"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Vnovičen zagon seje"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Ponastavitev naprave na tovarniške nastavitve za uporabo brez omejitev"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Dotaknite se, če želite izvedeti več."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index c3911eb..06c0d74 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"tani"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>m</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> min</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>o</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>o</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> orë</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> orë</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>d</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ditë</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ditë</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>v</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>v</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> vite</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> vit</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g>m</item>
-      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g>m</item>
+      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g> min</item>
+      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g> min</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g>o</item>
-      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g>o</item>
+      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g> orë</item>
+      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g> orë</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g>d</item>
-      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g>d</item>
+      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g> ditë</item>
+      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g> ditë</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g>v</item>
-      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g>v</item>
+      <item quantity="other">në <xliff:g id="COUNT_1">%d</xliff:g> vite</item>
+      <item quantity="one">në <xliff:g id="COUNT_0">%d</xliff:g> vit</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> minuta më parë</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Zhgozhdo"</string>
     <string name="app_info" msgid="6856026610594615344">"Informacioni mbi aplikacionin"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Rinis sesionin"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Trokit për të nisur një sesion të ri të demonstrimit"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demonstrimi po niset"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sesioni po riniset"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Rivendos cilësimet e fabrikës për ta përdorur këtë pajisje pa kufizime"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Prek për të mësuar më shumë."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 5b6dcd4..9b7f34d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -878,8 +878,8 @@
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> дан</item>
-      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> дан</item>
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> дан</item>
+      <item quantity="few"><xliff:g id="COUNT_1">%d</xliff:g> дана</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> дана</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
       <item quantity="one"><xliff:g id="COUNT_1">%d</xliff:g> год</item>
@@ -898,8 +898,8 @@
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
       <item quantity="one">за <xliff:g id="COUNT_1">%d</xliff:g> дан</item>
-      <item quantity="few">за <xliff:g id="COUNT_1">%d</xliff:g> дан</item>
-      <item quantity="other">за <xliff:g id="COUNT_1">%d</xliff:g> дан</item>
+      <item quantity="few">за <xliff:g id="COUNT_1">%d</xliff:g> дана</item>
+      <item quantity="other">за <xliff:g id="COUNT_1">%d</xliff:g> дана</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
       <item quantity="one">за <xliff:g id="COUNT_1">%d</xliff:g> год</item>
@@ -1685,6 +1685,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Откачи"</string>
     <string name="app_info" msgid="6856026610594615344">"Информације о апликацији"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Поново покрените сесију"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Додирните да бисте покренули нову сесију демонстрације"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Демонстрација се покреће"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Сесија се поново покреће"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Ресетујте уређај на фабричка подешавања да бисте га користили без ограничења"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Додирните да бисте сазнали више."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виџет <xliff:g id="LABEL">%1$s</xliff:g> је онемогућен"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9f78411..2168d96d6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Lossa"</string>
     <string name="app_info" msgid="6856026610594615344">"Info om appen"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Starta om sessionen"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Tryck om du vill starta en ny demosession"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo startas"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Sessionen startas om"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Återställ enheten till standardinställningarna om du vill använda den utan begränsningar"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Tryck här om du vill läsa mer."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 7ceef61..7e6f0338 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1647,6 +1647,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Bandua"</string>
     <string name="app_info" msgid="6856026610594615344">"Maelezo ya programu"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Anzisha Kipindi Upya"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Gonga ili uanzishe kipindi kipya cha onyesho"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Inaanzisha onyesho"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Inaanzisha onyesho upya"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Rejesha mipangilio iliyotoka nayo kiwandani ili utumie kifaa hiki bila vikwazo"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Gusa ili kupata maelezo zaidi."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 35f4254..03c3169 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -692,8 +692,8 @@
     <string name="lockscreen_transport_pause_description" msgid="3980308465056173363">"இடைநிறுத்து"</string>
     <string name="lockscreen_transport_play_description" msgid="1901258823643886401">"இயக்கு"</string>
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"நிறுத்து"</string>
-    <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"பின்னே செல்"</string>
-    <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"முன்னே செல்"</string>
+    <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"மீண்டும் காட்டு"</string>
+    <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"வேகமாக முன்செல்"</string>
     <string name="emergency_calls_only" msgid="6733978304386365407">"அவசர அழைப்புகள் மட்டும்"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"நெட்வொர்க் பூட்டப்பட்டது"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"சிம் கார்டு PUK பூட்டுதல் செய்யப்பட்டுள்ளது."</string>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"பின்னை அகற்று"</string>
     <string name="app_info" msgid="6856026610594615344">"பயன்பாட்டுத் தகவல்"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"அமர்வை மீண்டும் தொடங்கு"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"புதிய டெமோ அமர்வைத் தொடங்க, தட்டவும்"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"டெமோவைத் தொடங்குகிறது"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"அமர்வை மீண்டும் தொடங்குகிறது"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"இந்தச் சாதனத்தைக் கட்டுப்பாடுகளின்றிப் பயன்படுத்த, ஆரம்ப நிலைக்கு மீட்டமைக்கவும்"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"மேலும் அறிய தொடவும்."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"முடக்கப்பட்டது: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index bee79de..91976cc 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"ఇప్పుడు"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ని</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ని</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ని.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ని.</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>గం</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>గం</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> గం.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> గం.</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>రో</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>రో</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> రో.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> రో.</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>సం</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>సం</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> సం.</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> సం.</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ని.లో</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ని.లో</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ని.లో</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ని.లో</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>గంటల్లో</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>గంటలో</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> గం.లో</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> గం.లో</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>రోజుల్లో</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>రోజులో</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> రో.లో</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> రో.లో</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>సం.లో</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>సం.లో</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> సం.లో</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> సం.లో</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> నిమిషాల క్రితం</item>
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"అన్‌‌పిన్‌ ‌చేయి"</string>
     <string name="app_info" msgid="6856026610594615344">"అనువర్తన సమాచారం"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"సెషన్‌ను పునఃప్రారంభించండి"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"కొత్త డెమో సెషన్‌ను ప్రారంభించడానికి నొక్కండి"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"డెమోను ప్రారంభిస్తోంది"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"సెషన్‌ను పునఃప్రారంభిస్తోంది"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"ఈ పరికరాన్ని ఎటువంటి పరిమితులు లేకుండా ఉపయోగించడానికి ఫ్యాక్టరీ రీసెట్ చేయండి"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"మరింత తెలుసుకోవడానికి తాకండి."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> నిలిపివేయబడింది"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index ef1f9a1..c21d628 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"เลิกปักหมุด"</string>
     <string name="app_info" msgid="6856026610594615344">"ข้อมูลแอป"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"เริ่มเซสชันอีกครั้ง"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"แตะเพื่อเริ่มเซสชันสาธิตใหม่"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"กำลังเริ่มการสาธิต"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"กำลังเริ่มเซสชันอีกครั้ง"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"รีเซ็ตเป็นค่าเริ่มต้นเพื่อใช้อุปกรณ์นี้โดยไร้ข้อจำกัด"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"แตะเพื่อเรียนรู้เพิ่มเติม"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ปิดใช้ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 1bdc63a..269f249 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"I-unpin"</string>
     <string name="app_info" msgid="6856026610594615344">"Impormasyon ng app"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"I-restart ang Session"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"I-tap upang magsimula ng bagong session ng demo"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Sinisimulan ang demo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Nire-restart ang session"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"I-factory reset upang magamit ang device na ito nang walang mga paghihigpit"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Pindutin upang matuto nang higit pa."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 8f2dc75..aea719b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"şimdi"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>dk</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>dk</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dk</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> dk</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>sa</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>sa</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> sa</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> sa</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>g</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>g</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> g</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> g</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>y</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>y</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> y</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> y</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>dk içinde</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>dk içinde</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dk içinde</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> dk içinde</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>sa içinde</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>sa içinde</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> sa içinde</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> sa içinde</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>g içinde</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>g içinde</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> g içinde</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> g içinde</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>y içinde</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>y içinde</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> y içinde</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> y içinde</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> dakika önce</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Sabitlemeyi kaldır"</string>
     <string name="app_info" msgid="6856026610594615344">"Uygulama bilgileri"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Oturumu Yeniden Başlatın"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Yeni bir demo oturumu başlatmak için dokunun"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Tanıtım başlatılıyor"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Oturum yeniden başlatılıyor"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu cihazı kısıtlama olmadan kullanmak için fabrika ayarlarına sıfırlayın"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Daha fazla bilgi edinmek için dokunun."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 57ff67f..4e5bc1d 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -20,7 +20,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">"б"</string>
+    <string name="byteShort" msgid="8340973892742019101">"Б"</string>
     <string name="kilobyteShort" msgid="5973789783504771878">"Кб"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"Мб"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"Гб"</string>
@@ -1721,6 +1721,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Відкріпити"</string>
     <string name="app_info" msgid="6856026610594615344">"Про додаток"</string>
     <string name="negative_duration" msgid="5688706061127375131">"-<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Новий сеанс"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Торкніться, щоб почати новий демо-сеанс"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Запускається демонстрація"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Починається новий сеанс"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Відновіть заводські параметри, щоб використовувати пристрій без обмежень"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Торкніться, щоб дізнатися більше."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> вимкнено"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index a2dd131..4ae5cbf 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"پن ہٹائیں"</string>
     <string name="app_info" msgid="6856026610594615344">"ایپ کی معلومات"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"سیشن دوبارہ شروع کریں"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"نیا ڈیمو سیشن شروع کرنے کیلئے تھپتھپائیں"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"ڈیمو شروع ہو رہا ہے"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"سیشن دوبارہ شروع ہو رہا ہے"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"بغیر کسی حدود کے استعمال کرنے کیلئے اس آلے کو فیکٹری ری سیٹ کریں"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"مزید جاننے کیلئے ٹچ کریں۔"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"غیر فعال کردہ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index fb39be29..d777ea0 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -1652,6 +1652,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Olib tashlash"</string>
     <string name="app_info" msgid="6856026610594615344">"Ilova haqida"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Yangi seans"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Yangi demo-seans boshlash uchun bosing"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Demo boshlanmoqda"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Seans qayta boshlanmoqda"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Bu qurilmadan cheklovlarsiz foydalanish uchun zavod sozlamalarini tiklang"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Ko‘proq o‘rganish uchun bosing."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9ad9737..3998207 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"bây giờ"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ph</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ph</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> phút</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> phút</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>h</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> giờ</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> giờ</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>ng</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>ng</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> ngày</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> ngày</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>n</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>n</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> năm</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> năm</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other">sau <xliff:g id="COUNT_1">%d</xliff:g>ph</item>
-      <item quantity="one">sau <xliff:g id="COUNT_0">%d</xliff:g>ph</item>
+      <item quantity="other">trong <xliff:g id="COUNT_1">%d</xliff:g>ph</item>
+      <item quantity="one">trong <xliff:g id="COUNT_0">%d</xliff:g>ph</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other">sau <xliff:g id="COUNT_1">%d</xliff:g>h</item>
-      <item quantity="one">sau <xliff:g id="COUNT_0">%d</xliff:g>h</item>
+      <item quantity="other">trong <xliff:g id="COUNT_1">%d</xliff:g>h</item>
+      <item quantity="one">trong <xliff:g id="COUNT_0">%d</xliff:g>h</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other">sau <xliff:g id="COUNT_1">%d</xliff:g>ng</item>
-      <item quantity="one">sau <xliff:g id="COUNT_0">%d</xliff:g>ng</item>
+      <item quantity="other">trong <xliff:g id="COUNT_1">%d</xliff:g> ngày</item>
+      <item quantity="one">trong <xliff:g id="COUNT_0">%d</xliff:g> ngày</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other">sau <xliff:g id="COUNT_1">%d</xliff:g>n</item>
-      <item quantity="one">sau <xliff:g id="COUNT_0">%d</xliff:g>n</item>
+      <item quantity="other">trong <xliff:g id="COUNT_1">%d</xliff:g> năm</item>
+      <item quantity="one">trong <xliff:g id="COUNT_0">%d</xliff:g> năm</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> phút trước</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Bỏ ghim"</string>
     <string name="app_info" msgid="6856026610594615344">"Thông tin ứng dụng"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Khởi động lại phiên"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Nhấn để bắt đầu phiên trình diễn mới"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Bắt đầu bản trình diễn"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Bắt đầu lại phiên"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Khôi phục cài đặt gốc để sử dụng thiết bị này mà không bị hạn chế"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Chạm để tìm hiểu thêm."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 9336182..5bf0090 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1618,7 +1618,8 @@
     <string name="floating_toolbar_close_overflow_description" msgid="559796923090723804">"关闭工具栏溢出"</string>
     <string name="maximize_button_text" msgid="7543285286182446254">"最大化"</string>
     <string name="close_button_text" msgid="3937902162644062866">"关闭"</string>
-    <string name="notification_messaging_title_template" msgid="3452480118762691020">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>:<xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string>
+    <!-- no translation found for notification_messaging_title_template (3452480118762691020) -->
+    <skip />
     <plurals name="selected_count" formatted="false" msgid="7187339492915744615">
       <item quantity="other">已选择 <xliff:g id="COUNT_1">%1$d</xliff:g> 项</item>
       <item quantity="one">已选择 <xliff:g id="COUNT_0">%1$d</xliff:g> 项</item>
@@ -1649,6 +1650,12 @@
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"应用信息"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"重新启动会话"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"点按即可启动新的演示会话"</string>
+    <!-- no translation found for demo_starting_message (7574017688324606624) -->
+    <skip />
+    <!-- no translation found for demo_restarting_message (1363894248779727028) -->
+    <skip />
     <string name="audit_safemode_notification" msgid="6416076898350685856">"恢复出厂设置即可正常使用此设备,不受任何限制"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"触摸即可了解详情。"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index d7b705b..a791ccd 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資料"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"重新開始時段"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"輕按即可開始新示範時段"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"正在開始示範"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"正在重新開始示範時段"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"將此裝置回復至原廠設定後,使用將不受限制"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸以瞭解詳情。"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"「<xliff:g id="LABEL">%1$s</xliff:g>」已停用"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index cef8b98..395436e 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -860,36 +860,36 @@
     </plurals>
     <string name="now_string_shortest" msgid="8912796667087856402">"現在"</string>
     <plurals name="duration_minutes_shortest" formatted="false" msgid="3957499975064245495">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>分鐘</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>分鐘</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 分鐘</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 分鐘</item>
     </plurals>
     <plurals name="duration_hours_shortest" formatted="false" msgid="3552182110578602356">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>小時</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>小時</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 小時</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 小時</item>
     </plurals>
     <plurals name="duration_days_shortest" formatted="false" msgid="5213655532597081640">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>天</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>天</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 天</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 天</item>
     </plurals>
     <plurals name="duration_years_shortest" formatted="false" msgid="7848711145196397042">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>年</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>年</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 年</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 年</item>
     </plurals>
     <plurals name="duration_minutes_shortest_future" formatted="false" msgid="3277614521231489951">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>分鐘後</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>分鐘後</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 分鐘內</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 分鐘內</item>
     </plurals>
     <plurals name="duration_hours_shortest_future" formatted="false" msgid="2152452368397489370">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>小時後</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>小時後</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 小時內</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 小時內</item>
     </plurals>
     <plurals name="duration_days_shortest_future" formatted="false" msgid="8088331502820295701">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>天後</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>天後</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 天內</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 天內</item>
     </plurals>
     <plurals name="duration_years_shortest_future" formatted="false" msgid="2317006667145250301">
-      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g>年後</item>
-      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g>年後</item>
+      <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 年內</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%d</xliff:g> 年內</item>
     </plurals>
     <plurals name="duration_minutes_relative" formatted="false" msgid="3178131706192980192">
       <item quantity="other"><xliff:g id="COUNT_1">%d</xliff:g> 分鐘前</item>
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"取消固定"</string>
     <string name="app_info" msgid="6856026610594615344">"應用程式資訊"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"重新啟動工作階段"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"輕觸即可啟動新的示範工作階段"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"正在啟動示範模式"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"正在重新啟動工作階段"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"恢復原廠設定即可正常使用這個裝置"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"輕觸即可瞭解詳情。"</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 7720b5e..6f5a6ea 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1649,6 +1649,10 @@
     <string name="unpin_target" msgid="3556545602439143442">"Susa ukuphina"</string>
     <string name="app_info" msgid="6856026610594615344">"Ulwazi lohlelo lokusebenza"</string>
     <string name="negative_duration" msgid="5688706061127375131">"−<xliff:g id="TIME">%1$s</xliff:g>"</string>
+    <string name="reset_retail_demo_mode_title" msgid="2187220736280147886">"Qalisa kabusha isikhathi"</string>
+    <string name="reset_retail_demo_mode_text" msgid="5687062656885515019">"Thepha ukuze uqale isikhathi esisha sedemo"</string>
+    <string name="demo_starting_message" msgid="7574017688324606624">"Ukuqalisa idemo"</string>
+    <string name="demo_restarting_message" msgid="1363894248779727028">"Ukuqalisa kabusha iseshini"</string>
     <string name="audit_safemode_notification" msgid="6416076898350685856">"Setha kabusha ukuze usebenzise idivayisi ngaphandle kwemikhawulo"</string>
     <string name="audit_safemode_notification_details" msgid="1860601176690176413">"Thinta ukuze ufunde kabanzi."</string>
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index b61d6cf..d0c6a8e 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1832,6 +1832,10 @@
         <enum name="KEYCODE_CUT" value="277" />
         <enum name="KEYCODE_COPY" value="278" />
         <enum name="KEYCODE_PASTE" value="279" />
+        <enum name="KEYCODE_FP_NAV_UP" value="280" />
+        <enum name="KEYCODE_FP_NAV_DOWN" value="281" />
+        <enum name="KEYCODE_FP_NAV_LEFT" value="282" />
+        <enum name="KEYCODE_FP_NAV_RIGHT" value="283" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -2043,6 +2047,13 @@
         <attr name="showTitle" format="boolean" />
         <!-- @hide Whether fullDark, etc. should use default values if null. -->
         <attr name="needsDefaultBackgrounds" format="boolean" />
+        <!-- @hide Workaround until we replace AlertController with custom layout. -->
+        <attr name="controllerType">
+            <!-- The default controller. -->
+            <enum name="normal" value="0" />
+            <!-- Controller for micro specific layout. -->
+            <enum name="micro" value="1" />
+        </attr>
     </declare-styleable>
 
     <!-- @hide -->
@@ -7324,14 +7335,24 @@
     <declare-styleable name="Wallpaper">
         <attr name="settingsActivity" />
 
-        <!-- Reference to a the wallpaper's thumbnail bitmap. -->
+        <!-- Reference to the wallpaper's thumbnail bitmap. -->
         <attr name="thumbnail" format="reference" />
 
-        <!-- Name of the author of this component, e.g. Google. -->
+        <!-- Name of the author and/or source/collection of this component, e.g. Art Collection, Picasso. -->
         <attr name="author" format="reference" />
 
         <!-- Short description of the component's purpose or behavior. -->
         <attr name="description" />
+
+        <!-- Uri that specifies a link for further context of this wallpaper, e.g. http://www.picasso.org. -->
+        <attr name="contextUri" format="reference" />
+
+        <!-- Title of the uri that specifies a link for further context of this wallpaper, e.g. Explore collection. -->
+        <attr name="contextDescription" format="reference" />
+
+        <!-- Whether to show any metadata when previewing the wallpaper. -->
+        <attr name="showMetadataInPreview" format="boolean" />
+
     </declare-styleable>
 
     <!-- Use <code>dream</code> as the root tag of the XML resource that
@@ -8226,4 +8247,16 @@
                    color. -->
         <attr name="colorBackground" />
     </declare-styleable>
+
+    <declare-styleable name="Shortcut">
+        <attr name="shortcutId" format="string" />
+        <attr name="enabled" />
+        <attr name="shortcutIcon" format="reference" />
+        <attr name="shortcutShortLabel" format="reference" />
+        <attr name="shortcutLongLabel" format="reference" />
+        <attr name="shortcutDisabledMessage" format="reference" />
+        <attr name="shortcutCategories" format="string" />
+        <attr name="shortcutIntentAction" format="string" />
+        <attr name="shortcutIntentData" format="string" />
+    </declare-styleable>
 </resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index d69d73d..0872ef9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -62,6 +62,20 @@
          a reference to a Drawable resource containing the image definition. -->
     <attr name="icon" format="reference" />
 
+    <!-- A Drawable resource providing a graphical representation of its
+         associated item.  Use with the
+         application tag (to supply a default round icon for all application
+         components), or with the activity, receiver, service, or instrumentation
+         tag (to supply a specific round icon for that component).  It may also be
+         used with the intent-filter tag to supply a round icon to show to the
+         user when an activity is being selected based on a particular Intent.
+
+         <p>The given round icon will be used to display to the user a graphical
+         representation of its associated component; for example, as the round icon
+         for main activity that is displayed in the launcher.  This must be
+         a reference to a Drawable resource containing the image definition. -->
+    <attr name="roundIcon" format="reference" />
+
     <!-- A Drawable resource providing an extended graphical banner for its
          associated item. Use with the application tag (to supply a default
          banner for all application activities), or with the activity, tag to
@@ -1236,6 +1250,7 @@
         <attr name="theme" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
@@ -1335,6 +1350,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="permissionGroup" />
@@ -1362,6 +1378,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="description" />
@@ -1395,6 +1412,7 @@
         <attr name="name" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
@@ -1676,6 +1694,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="process" />
@@ -1759,6 +1778,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
@@ -1807,6 +1827,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
@@ -1843,6 +1864,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="launchMode" />
@@ -1926,6 +1948,7 @@
         <attr name="label" />
         <attr name="description" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="permission" />
@@ -1998,6 +2021,7 @@
          parent="AndroidManifestActivity AndroidManifestReceiver AndroidManifestService">
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="priority" />
@@ -2128,6 +2152,7 @@
         <attr name="targetPackage" />
         <attr name="label" />
         <attr name="icon" />
+        <attr name="roundIcon" />
         <attr name="banner" />
         <attr name="logo" />
         <attr name="handleProfiling" />
diff --git a/core/res/res/values/colors_micro.xml b/core/res/res/values/colors_micro.xml
new file mode 100644
index 0000000..b268e9a
--- /dev/null
+++ b/core/res/res/values/colors_micro.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+    <color name="foreground_micro_dark">@color/white</color>
+    <color name="foreground_micro_light">@color/black</color>
+
+    <color name="background_micro_dark">@color/micro_blue_grey_b15</color>
+    <color name="background_micro_light">@color/white</color>
+    <color name="background_floating_micro_dark">@color/micro_blue_grey_b30</color>
+    <color name="background_floating_micro_light">@color/micro_blue_grey_500</color>
+
+    <color name="primary_micro_dark">@color/micro_blue_grey_b65</color>
+    <color name="primary_dark_micro_dark">@color/micro_blue_grey_b40</color>
+
+    <color name="accent_micro_light">@color/micro_blue_grey_500</color>
+    <color name="accent_micro_dark">@color/micro_blue_grey_b100</color>
+
+    <color name="button_micro_dark">@color/micro_button_gray</color>
+
+    <!-- Primary & accent colors -->
+    <eat-comment />
+
+    <!-- App color -->
+    <color name="micro_blue_grey_500">#ff607d8b</color>
+    <!-- Accent -->
+    <color name="micro_blue_grey_b100">#ffb0e5ff</color>
+    <!-- Lighter UI element -->
+    <color name="micro_blue_grey_b65">#ff7295a6</color>
+    <!-- UI Element -->
+    <color name="micro_blue_grey_b40">#ff465b66</color>
+    <!-- Lighter background -->
+    <color name="micro_blue_grey_b30">#ff35454d</color>
+    <!-- Dark background -->
+    <color name="micro_blue_grey_b15">#ff1a2226</color>
+
+    <!-- Button colors -->
+    <eat-comment />
+
+    <color name="micro_confirm_green">#ff4fc0b0</color>
+    <color name="micro_button_gray">#ffc2c2c2</color>
+    <color name="micro_action_blue">#ff0288d1</color>
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d0fd36a..be2cc23 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2486,4 +2486,7 @@
     <string-array translatable="false" name="config_defaultPinnerServiceFiles">
     </string-array>
 
+    <!-- Component that is the default launcher when demo mode is enabled. -->
+    <string name="config_demoModeLauncherComponent"></string>
+
 </resources>
diff --git a/core/res/res/values/dimens_micro.xml b/core/res/res/values/dimens_micro.xml
new file mode 100644
index 0000000..dc8b124
--- /dev/null
+++ b/core/res/res/values/dimens_micro.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<resources>
+    <dimen name="text_size_headline_micro">22sp</dimen>
+    <dimen name="text_size_title_micro">20sp</dimen>
+    <dimen name="text_size_subtitle_micro">18sp</dimen>
+    <dimen name="text_size_body1_micro">16sp</dimen>
+    <dimen name="text_size_body2_micro">14sp</dimen>
+    <dimen name="text_size_caption_micro">12sp</dimen>
+
+    <dimen name="text_size_large_micro">20sp</dimen>
+    <dimen name="text_size_medium_micro">18sp</dimen>
+    <dimen name="text_size_small_micro">16sp</dimen>
+
+    <item name="line_spacing_multiplier_micro" format="float" type="dimen">1.2</item>
+</resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6797799..da31767 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2728,4 +2728,22 @@
     <public type="id" name="icon_frame" id="0x0102003e" />
     <public type="id" name="list_container" id="0x0102003f" />
     <public type="id" name="switch_widget" id="0x01020040" />
+  <!-- ===============================================================
+       Resources added in version N MR1 of the platform
+       =============================================================== -->
+    <eat-comment />
+    <public type="attr" name="shortcutId" />
+    <public type="attr" name="shortcutIcon" />
+    <public type="attr" name="shortcutShortLabel" />
+    <public type="attr" name="shortcutLongLabel" />
+    <public type="attr" name="shortcutDisabledMessage" />
+    <public type="attr" name="shortcutCategories" />
+    <public type="attr" name="shortcutIntentAction" />
+    <public type="attr" name="shortcutIntentData" />
+    <public type="attr" name="roundIcon" />
+
+    <public type="attr" name="contextUri" />
+    <public type="attr" name="contextDescription" />
+    <public type="attr" name="showMetadataInPreview" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 48744b6..5db562d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4366,6 +4366,17 @@
     <!-- The representation of a time duration when negative. An example is -1:14. This can be used with a countdown timer for example.-->
     <string name="negative_duration">\u2212<xliff:g id="time" example="1:14">%1$s</xliff:g></string>
 
+    <!-- Title of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
+    <string name="reset_retail_demo_mode_title">Restart Session</string>
+    <!-- Text of notification to start a new demo session when device is in retail mode [CHAR LIMIT=NONE] -->
+    <string name="reset_retail_demo_mode_text">Tap to start a new demo session</string>
+    <!-- Text of dialog shown when starting a demo user for the first time [CHAR LIMIT=40] -->
+    <string name="demo_starting_message">Starting demo</string>
+    <!-- Text of dialog shown when starting a new demo user in retail demo mode [CHAR LIMIT=40] -->
+    <string name="demo_restarting_message">Restarting session</string>
+
+
+
     <!-- Title of notification shown when device has been forced to safe mode after a security compromise. -->
     <string name="audit_safemode_notification">Factory reset to use this device without restrictions</string>
     <!-- Description of notification shown when device has been forced to safe mode after a security compromise. -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 790dcfa..273086d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1122,6 +1122,8 @@
     <style name="PreferenceFragmentList">
         <item name="paddingStart">@dimen/preference_fragment_padding_side</item>
         <item name="paddingEnd">@dimen/preference_fragment_padding_side</item>
+        <item name="paddingTop">0dp</item>
+        <item name="paddingBottom">@dimen/preference_fragment_padding_bottom</item>
     </style>
 
     <!-- Other Misc Styles -->
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index 341a0a4c..aecf982 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -40,7 +40,7 @@
         <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
     </style>
 
-    <style name="AlertDialog.Micro" parent="AlertDialog.Material.Light">
+    <style name="AlertDialog.Micro" parent="AlertDialog.Material">
         <item name="fullDark">@null</item>
         <item name="topDark">@null</item>
         <item name="centerDark">@null</item>
@@ -52,30 +52,83 @@
         <item name="bottomMedium">@null</item>
         <item name="centerMedium">@null</item>
         <item name="layout">@layout/alert_dialog_micro</item>
+        <item name="controllerType">micro</item>
     </style>
 
     <style name="DialogWindowTitle.Micro">
-        <item name="maxLines">1</item>
         <item name="scrollHorizontally">true</item>
         <item name="textAppearance">@style/TextAppearance.Micro.DialogWindowTitle</item>
+        <item name="textAlignment">viewStart</item>
     </style>
 
     <style name="TextAppearance.Micro" parent="TextAppearance.Material">
-        <item name="textSize">20sp</item>
         <item name="fontFamily">sans-serif-condensed-light</item>
-        <item name="textColor">@color/micro_text_light</item>
+        <item name="lineSpacingMultiplier">@dimen/line_spacing_multiplier_micro</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+        <item name="textSize">@dimen/text_size_medium_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Inverse" parent="TextAppearance.Material">
+        <item name="textColor">?attr/textColorPrimaryInverse</item>
+        <item name="textColorHint">?attr/textColorHintInverse</item>
+        <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
+        <item name="textColorLink">?attr/textColorLinkInverse</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Headline">
+        <item name="textSize">@dimen/text_size_headline_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Title">
+        <item name="textSize">@dimen/text_size_title_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Subtitle">
+        <item name="textSize">@dimen/text_size_subtitle_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Body1">
+        <item name="textSize">@dimen/text_size_body1_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Body2">
+        <item name="textSize">@dimen/text_size_body2_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Caption">
+        <item name="textSize">@dimen/text_size_caption_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Large">
+        <item name="textSize">@dimen/text_size_large_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Medium">
+        <item name="textSize">@dimen/text_size_medium_micro</item>
+    </style>
+
+    <style name="TextAppearance.Micro.Small">
+        <item name="textSize">@dimen/text_size_small_micro</item>
     </style>
 
     <style name="TextAppearance.Micro.DialogWindowTitle" parent="TextAppearance.Material.DialogWindowTitle">
-        <item name="textSize">20sp</item>
         <item name="fontFamily">sans-serif-condensed-light</item>
-        <item name="textColor">@color/micro_text_light</item>
+        <item name="lineSpacingMultiplier">@dimen/line_spacing_multiplier_micro</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+        <item name="textSize">@dimen/text_size_large_micro</item>
     </style>
 
+    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small" />
+
     <style name="Widget.Micro" parent="Widget.Material" />
 
-    <style name="Widget.Micro.TextView">
-        <item name="fontFamily">sans-serif-condensed</item>
+    <style name="Widget.Micro.TextView" parent="Widget.Material.TextView" >
+        <item name="breakStrategy">balanced</item>
+        <item name="hyphenationFrequency">normal</item>
+    </style>
+
+    <style name="Widget.Micro.EditText" parent="Widget.Material.EditText">
+        <item name="android:breakStrategy">simple</item>
     </style>
 
     <style name="Widget.Micro.NumberPicker">
@@ -90,4 +143,14 @@
         <item name="descendantFocusability">blocksDescendants</item>
     </style>
 
+    <style name="Widget.Micro.ButtonBar">
+        <item name="background">@color/background_floating_micro_dark</item>
+    </style>
+
+    <style name="Widget.Micro.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.ButtonBar.AlertDialog">
+        <item name="textAppearance">@style/TextAppearance.Micro.Small</item>
+        <item name="maxLines">3</item>
+        <item name="textColor">?attr/textColorPrimary</item>
+        <item name="textAlignment">viewStart</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index abef7f8..8edd9d1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1103,6 +1103,10 @@
   <java-symbol type="string" name="lockscreen_transport_pause_description" />
   <java-symbol type="string" name="config_ethernet_tcp_buffers" />
   <java-symbol type="string" name="config_wifi_tcp_buffers" />
+  <java-symbol type="string" name="config_demoModeLauncherComponent" />
+  <java-symbol type="string" name="demo_starting_message" />
+  <java-symbol type="string" name="demo_restarting_message" />
+
 
   <java-symbol type="plurals" name="bugreport_countdown" />
   <java-symbol type="plurals" name="duration_hours" />
@@ -1887,6 +1891,8 @@
   <java-symbol type="string" name="config_persistentDataPackageName" />
   <java-symbol type="string" name="audit_safemode_notification" />
   <java-symbol type="string" name="audit_safemode_notification_details" />
+  <java-symbol type="string" name="reset_retail_demo_mode_title" />
+  <java-symbol type="string" name="reset_retail_demo_mode_text" />
 
   <java-symbol type="layout" name="resolver_list" />
   <java-symbol type="id" name="resolver_list" />
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
index 25a6e00..63a6a484 100644
--- a/core/res/res/values/themes_micro.xml
+++ b/core/res/res/values/themes_micro.xml
@@ -19,13 +19,43 @@
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
         <item name="textViewStyle">@style/Widget.Micro.TextView</item>
+        <item name="editTextStyle">@style/Widget.Micro.EditText</item>
         <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
         <item name="windowAnimationStyle">@style/Animation.Micro.Activity</item>
-        <item name="windowBackground">@color/black</item>
+        <item name="windowBackground">@color/background_micro_dark</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
+
+        <item name="textAppearance">@style/TextAppearance.Micro</item>
+        <item name="textAppearanceInverse">@style/TextAppearance.Micro.Inverse</item>
+
+        <item name="textAppearanceLarge">@style/TextAppearance.Micro.Large</item>
+        <item name="textAppearanceMedium">@style/TextAppearance.Micro.Medium</item>
+        <item name="textAppearanceSmall">@style/TextAppearance.Micro.Small</item>
+
+        <item name="textAppearanceListItem">@style/TextAppearance.Micro.Subtitle</item>
+        <item name="textAppearanceListItemSmall">@style/TextAppearance.Micro.Body1</item>
+        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Micro.Body2</item>
+        <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_left_micro</item>
+        <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_right_micro</item>
+        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_left_micro</item>
+        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_right_micro</item>
+
+        <!-- Dialog styling -->
+        <item name="buttonBarStyle">@style/Widget.Micro.ButtonBar</item>
+        <item name="buttonBarButtonStyle">@style/Widget.Micro.Button.ButtonBar.AlertDialog</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimaryDark">@color/primary_dark_micro_dark</item>
+        <item name="colorPrimary">@color/primary_micro_dark</item>
+        <item name="colorAccent">@color/accent_micro_dark</item>
+        <item name="colorEdgeEffect">?attr/colorPrimary</item>
+
+        <!-- Preference styles -->
+        <item name="preferenceFragmentStyle">@style/PreferenceFragment.Micro</item>
+        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Micro</item>
     </style>
 
     <style name="Theme.Micro" parent="Theme.MicroBase">
@@ -49,12 +79,29 @@
     <style name="Theme.Micro.Light" parent="Theme.Micro.LightBase">
     </style>
 
-    <style name="Theme.Micro.DialogBase" parent="Theme.Material.Light.Dialog">
-        <item name="windowTitleStyle">@android:style/DialogWindowTitle.Micro</item>
+    <style name="Theme.Micro.DialogBase">
+        <item name="colorBackground">?attr/colorBackgroundFloating</item>
+
+        <item name="windowFrame">@null</item>
+        <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
+        <item name="windowElevation">@dimen/floating_window_z</item>
+        <item name="windowContentOverlay">@null</item>
+        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
+        <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
+        <item name="windowActionBar">false</item>
+        <item name="windowActionModeOverlay">true</item>
+        <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
+
+        <item name="colorBackgroundCacheHint">@null</item>
+
+        <item name="listDivider">@null</item>
+
+        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
+
+        <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
         <item name="windowIsFloating">false</item>
         <item name="windowFullscreen">true</item>
-        <item name="textAppearance">@style/TextAppearance.Micro</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Micro</item>
+        <item name="windowBackground">@color/background_micro_dark</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
     </style>
@@ -67,21 +114,17 @@
         <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowBackground">@android:color/transparent</item>
         <item name="windowOverscan">true</item>
         <item name="windowContentOverlay">@null</item>
-        <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
-        <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
+        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
+        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
     </style>
 
     <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
-        <item name="windowBackground">@null</item>
         <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
+        <item name="textAppearance">@style/TextAppearance.Micro.Large</item>
         <item name="windowOverscan">true</item>
         <item name="windowCloseOnTouchOutside">false</item>
-        <item name="textSize">20sp</item>
-        <item name="fontFamily">sans-serif-condensed-light</item>
-        <item name="textColor">@color/micro_text_light</item>
     </style>
 
    <style name="Theme.Micro.Panel" parent="Theme.Material.Panel"  />
diff --git a/core/res/res/xml-watch/default_zen_mode_config.xml b/core/res/res/xml-watch/default_zen_mode_config.xml
new file mode 100644
index 0000000..26af10c
--- /dev/null
+++ b/core/res/res/xml-watch/default_zen_mode_config.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+    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.
+-->
+
+<!-- Default configuration for zen mode.  See android.service.notification.ZenModeConfig. -->
+<zen version="2">
+    <!-- Allow starred contacts to go through only. Repeated calls on.
+         Calls, messages, reminders, events off.-->
+    <allow from="2" repeatCallers="true" calls="false" messages="false" reminders="false"
+           events="false"/>
+</zen>
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
index 755e7c4..31ce95e 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothStressTest.java
@@ -35,6 +35,7 @@
     /** The amount of time to sleep between issuing start/stop SCO in ms. */
     private static final long SCO_SLEEP_TIME = 2 * 1000;
 
+    private BluetoothAdapter mAdapter;
     private BluetoothTestUtils mTestUtils;
 
     @Override
@@ -42,13 +43,18 @@
         super.setUp();
 
         Context context = getInstrumentation().getTargetContext();
+        mAdapter = BluetoothAdapter.getDefaultAdapter();
         mTestUtils = new BluetoothTestUtils(context, TAG, OUTPUT_FILE);
+
+        // Start all tests in a disabled state.
+        if (mAdapter.isEnabled()) {
+            mTestUtils.disable(mAdapter);
+        }
     }
 
     @Override
     protected void tearDown() throws Exception {
         super.tearDown();
-
         mTestUtils.close();
     }
 
@@ -61,13 +67,10 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mTestUtils.disable(adapter);
-
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("enable iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.enable(adapter);
-            mTestUtils.disable(adapter);
+            mTestUtils.enable(mAdapter);
+            mTestUtils.disable(mAdapter);
         }
     }
 
@@ -80,18 +83,14 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.undiscoverable(adapter);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.undiscoverable(mAdapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("discoverable iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.discoverable(adapter);
-            mTestUtils.undiscoverable(adapter);
+            mTestUtils.discoverable(mAdapter);
+            mTestUtils.undiscoverable(mAdapter);
         }
-
-        mTestUtils.disable(adapter);
     }
 
     /**
@@ -103,18 +102,14 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.stopScan(adapter);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.stopScan(mAdapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("scan iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.startScan(adapter);
-            mTestUtils.stopScan(adapter);
+            mTestUtils.startScan(mAdapter);
+            mTestUtils.stopScan(mAdapter);
         }
-
-        mTestUtils.disable(adapter);
     }
 
     /**
@@ -125,19 +120,16 @@
         if (iterations == 0) {
             return;
         }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.disablePan(adapter);
+
+        mTestUtils.enable(mAdapter);
+        mTestUtils.disablePan(mAdapter);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("testEnablePan iteration " + (i + 1) + " of "
                     + iterations);
-            mTestUtils.enablePan(adapter);
-            mTestUtils.disablePan(adapter);
+            mTestUtils.enablePan(mAdapter);
+            mTestUtils.disablePan(mAdapter);
         }
-
-        mTestUtils.disable(adapter);
     }
 
     /**
@@ -152,19 +144,16 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("pair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+            mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                     BluetoothTestRunner.sDevicePairPin);
-            mTestUtils.unpair(adapter, device);
+            mTestUtils.unpair(mAdapter, device);
         }
-        mTestUtils.disable(adapter);
     }
 
     /**
@@ -178,19 +167,16 @@
         if (iterations == 0) {
             return;
         }
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("acceptPair iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+            mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                     BluetoothTestRunner.sDevicePairPin);
-            mTestUtils.unpair(adapter, device);
+            mTestUtils.unpair(mAdapter, device);
         }
-        mTestUtils.disable(adapter);
     }
 
     /**
@@ -205,25 +191,22 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP, null);
+        mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectA2dp iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.A2DP,
+            mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.A2DP,
                     String.format("connectA2dp(device=%s)", device));
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.A2DP,
+            mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.A2DP,
                     String.format("disconnectA2dp(device=%s)", device));
         }
 
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disable(adapter);
+        mTestUtils.unpair(mAdapter, device);
     }
 
     /**
@@ -238,25 +221,22 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectHeadset iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET,
+            mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET,
                     String.format("connectHeadset(device=%s)", device));
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET,
+            mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET,
                     String.format("disconnectHeadset(device=%s)", device));
         }
 
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disable(adapter);
+        mTestUtils.unpair(mAdapter, device);
     }
 
     /**
@@ -271,25 +251,22 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE, null);
+        mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.INPUT_DEVICE, null);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectInput iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+            mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.INPUT_DEVICE,
                     String.format("connectInput(device=%s)", device));
-            mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.INPUT_DEVICE,
+            mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.INPUT_DEVICE,
                     String.format("disconnectInput(device=%s)", device));
         }
 
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disable(adapter);
+        mTestUtils.unpair(mAdapter, device);
     }
 
     /**
@@ -304,22 +281,19 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("connectPan iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.connectPan(adapter, device);
-            mTestUtils.disconnectPan(adapter, device);
+            mTestUtils.connectPan(mAdapter, device);
+            mTestUtils.disconnectPan(mAdapter, device);
         }
 
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disable(adapter);
+        mTestUtils.unpair(mAdapter, device);
     }
 
     /**
@@ -334,26 +308,23 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.disablePan(adapter);
-        mTestUtils.enablePan(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.acceptPair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.disablePan(mAdapter);
+        mTestUtils.enablePan(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.acceptPair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("incomingPanConnection iteration " + (i + 1) + " of "
                     + iterations);
-            mTestUtils.incomingPanConnection(adapter, device);
-            mTestUtils.incomingPanDisconnection(adapter, device);
+            mTestUtils.incomingPanConnection(mAdapter, device);
+            mTestUtils.incomingPanDisconnection(mAdapter, device);
         }
 
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disablePan(adapter);
-        mTestUtils.disable(adapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.disablePan(mAdapter);
     }
 
     /**
@@ -368,28 +339,25 @@
             return;
         }
 
-        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
-        BluetoothDevice device = adapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
-        mTestUtils.disable(adapter);
-        mTestUtils.enable(adapter);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.pair(adapter, device, BluetoothTestRunner.sDevicePairPasskey,
+        BluetoothDevice device = mAdapter.getRemoteDevice(BluetoothTestRunner.sDeviceAddress);
+        mTestUtils.enable(mAdapter);
+        mTestUtils.unpair(mAdapter, device);
+        mTestUtils.pair(mAdapter, device, BluetoothTestRunner.sDevicePairPasskey,
                 BluetoothTestRunner.sDevicePairPin);
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
-        mTestUtils.connectProfile(adapter, device, BluetoothProfile.HEADSET, null);
-        mTestUtils.stopSco(adapter, device);
+        mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.connectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.stopSco(mAdapter, device);
 
         for (int i = 0; i < iterations; i++) {
             mTestUtils.writeOutput("startStopSco iteration " + (i + 1) + " of " + iterations);
-            mTestUtils.startSco(adapter, device);
+            mTestUtils.startSco(mAdapter, device);
             sleep(SCO_SLEEP_TIME);
-            mTestUtils.stopSco(adapter, device);
+            mTestUtils.stopSco(mAdapter, device);
             sleep(SCO_SLEEP_TIME);
         }
 
-        mTestUtils.disconnectProfile(adapter, device, BluetoothProfile.HEADSET, null);
-        mTestUtils.unpair(adapter, device);
-        mTestUtils.disable(adapter);
+        mTestUtils.disconnectProfile(mAdapter, device, BluetoothProfile.HEADSET, null);
+        mTestUtils.unpair(mAdapter, device);
     }
 
     private void sleep(long time) {
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
index 0d9980a..a7ea43e 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothTestUtils.java
@@ -35,6 +35,8 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
 
 public class BluetoothTestUtils extends Assert {
 
@@ -425,33 +427,14 @@
     public void enable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_ON_FLAG | BluetoothReceiver.STATE_ON_FLAG
                 | BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG);
-        long start = -1;
+        long start = System.currentTimeMillis();
         BluetoothReceiver receiver = getBluetoothReceiver(mask);
 
-        int state = adapter.getState();
-        switch (state) {
-            case BluetoothAdapter.STATE_ON:
-                assertTrue(adapter.isEnabled());
-                removeReceiver(receiver);
-                return;
-            case BluetoothAdapter.STATE_TURNING_ON:
-                assertFalse(adapter.isEnabled());
-                mask = 0; // Don't check for received intents since we might have missed them.
-                break;
-            case BluetoothAdapter.STATE_OFF:
-                assertFalse(adapter.isEnabled());
-                start = System.currentTimeMillis();
-                assertTrue(adapter.enable());
-                break;
-            case BluetoothAdapter.STATE_TURNING_OFF:
-                start = System.currentTimeMillis();
-                assertTrue(adapter.enable());
-                break;
-            default:
-                removeReceiver(receiver);
-                fail(String.format("enable() invalid state: state=%d", state));
-        }
+        writeOutput("Enabling Bluetooth adapter.");
+        assertFalse(adapter.isEnabled());
+        assertTrue(adapter.enable());
 
+        int state = BluetoothAdapter.STATE_OFF;
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
@@ -485,33 +468,14 @@
     public void disable(BluetoothAdapter adapter) {
         int mask = (BluetoothReceiver.STATE_TURNING_OFF_FLAG | BluetoothReceiver.STATE_OFF_FLAG
                 | BluetoothReceiver.SCAN_MODE_NONE_FLAG);
-        long start = -1;
+        long start = System.currentTimeMillis();
         BluetoothReceiver receiver = getBluetoothReceiver(mask);
 
-        int state = adapter.getState();
-        switch (state) {
-            case BluetoothAdapter.STATE_OFF:
-                assertFalse(adapter.isEnabled());
-                removeReceiver(receiver);
-                return;
-            case BluetoothAdapter.STATE_TURNING_ON:
-                assertFalse(adapter.isEnabled());
-                start = System.currentTimeMillis();
-                break;
-            case BluetoothAdapter.STATE_ON:
-                assertTrue(adapter.isEnabled());
-                start = System.currentTimeMillis();
-                assertTrue(adapter.disable());
-                break;
-            case BluetoothAdapter.STATE_TURNING_OFF:
-                assertFalse(adapter.isEnabled());
-                mask = 0; // Don't check for received intents since we might have missed them.
-                break;
-            default:
-                removeReceiver(receiver);
-                fail(String.format("disable() invalid state: state=%d", state));
-        }
+        writeOutput("Disabling Bluetooth adapter.");
+        assertTrue(adapter.isEnabled());
+        assertTrue(adapter.disable());
 
+        int state = BluetoothAdapter.STATE_OFF;
         long s = System.currentTimeMillis();
         while (System.currentTimeMillis() - s < ENABLE_DISABLE_TIMEOUT) {
             state = adapter.getState();
@@ -543,40 +507,47 @@
      * @param adapter The BT adapter.
      */
     public void discoverable(BluetoothAdapter adapter) {
-        int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_DISCOVERABLE_FLAG;
-
         if (!adapter.isEnabled()) {
             fail("discoverable() bluetooth not enabled");
         }
 
         int scanMode = adapter.getScanMode();
-        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+        if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
             return;
         }
 
-        BluetoothReceiver receiver = getBluetoothReceiver(mask);
-
-        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE, scanMode);
-        long start = System.currentTimeMillis();
-        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
-
-        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
-            scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE
-                    && (receiver.getFiredFlags() & mask) == mask) {
-                writeOutput(String.format("discoverable() completed in %d ms",
-                        (receiver.getCompletedTime() - start)));
-                removeReceiver(receiver);
-                return;
+        final Semaphore completionSemaphore = new Semaphore(0);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String action = intent.getAction();
+                if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
+                    return;
+                }
+                final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
+                        BluetoothAdapter.SCAN_MODE_NONE);
+                if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
+                    completionSemaphore.release();
+                }
             }
-            sleep(POLL_TIME);
-        }
+        };
 
-        int firedFlags = receiver.getFiredFlags();
-        removeReceiver(receiver);
-        fail(String.format("discoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
-                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE,
-                firedFlags, mask));
+        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+        mContext.registerReceiver(receiver, filter);
+        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
+        boolean success = false;
+        try {
+            success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
+                    TimeUnit.MILLISECONDS);
+            writeOutput(String.format("discoverable() completed in 0 ms"));
+        } catch (final InterruptedException e) {
+            // This should never happen but just in case it does, the test will fail anyway.
+        }
+        mContext.unregisterReceiver(receiver);
+        if (!success) {
+            fail(String.format("discoverable() timeout: scanMode=%d (expected %d)", scanMode,
+                    BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE));
+        }
     }
 
     /**
@@ -586,40 +557,47 @@
      * @param adapter The BT adapter.
      */
     public void undiscoverable(BluetoothAdapter adapter) {
-        int mask = BluetoothReceiver.SCAN_MODE_CONNECTABLE_FLAG;
-
         if (!adapter.isEnabled()) {
             fail("undiscoverable() bluetooth not enabled");
         }
 
         int scanMode = adapter.getScanMode();
-        if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+        if (scanMode != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
             return;
         }
 
-        BluetoothReceiver receiver = getBluetoothReceiver(mask);
-
-        assertEquals(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, scanMode);
-        long start = System.currentTimeMillis();
-        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
-
-        while (System.currentTimeMillis() - start < DISCOVERABLE_UNDISCOVERABLE_TIMEOUT) {
-            scanMode = adapter.getScanMode();
-            if (scanMode == BluetoothAdapter.SCAN_MODE_CONNECTABLE
-                    && (receiver.getFiredFlags() & mask) == mask) {
-                writeOutput(String.format("undiscoverable() completed in %d ms",
-                        (receiver.getCompletedTime() - start)));
-                removeReceiver(receiver);
-                return;
+        final Semaphore completionSemaphore = new Semaphore(0);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final String action = intent.getAction();
+                if (!BluetoothAdapter.ACTION_SCAN_MODE_CHANGED.equals(action)) {
+                    return;
+                }
+                final int mode = intent.getIntExtra(BluetoothAdapter.EXTRA_SCAN_MODE,
+                        BluetoothAdapter.SCAN_MODE_NONE);
+                if (mode == BluetoothAdapter.SCAN_MODE_CONNECTABLE) {
+                    completionSemaphore.release();
+                }
             }
-            sleep(POLL_TIME);
-        }
+        };
 
-        int firedFlags = receiver.getFiredFlags();
-        removeReceiver(receiver);
-        fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d), flags=0x%x "
-                + "(expected 0x%x)", scanMode, BluetoothAdapter.SCAN_MODE_CONNECTABLE, firedFlags,
-                mask));
+        final IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
+        mContext.registerReceiver(receiver, filter);
+        assertTrue(adapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+        boolean success = false;
+        try {
+            success = completionSemaphore.tryAcquire(DISCOVERABLE_UNDISCOVERABLE_TIMEOUT,
+                    TimeUnit.MILLISECONDS);
+            writeOutput(String.format("undiscoverable() completed in 0 ms"));
+        } catch (InterruptedException e) {
+            // This should never happen but just in case it does, the test will fail anyway.
+        }
+        mContext.unregisterReceiver(receiver);
+        if (!success) {
+            fail(String.format("undiscoverable() timeout: scanMode=%d (expected %d)", scanMode,
+                    BluetoothAdapter.SCAN_MODE_CONNECTABLE));
+        }
     }
 
     /**
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
index da8bc1d..7935880 100644
--- a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -45,6 +45,7 @@
     private static final int TEST_CMD = 18;
     private static final int TEST_ARG1 = 33;
     private static final int TEST_ARG2 = 182;
+    private static final Object TEST_OBJ = "hello";
 
     @Mock AlarmManager mAlarmManager;
     WakeupMessage mMessage;
@@ -92,7 +93,7 @@
                 mListenerCaptor.capture(), any(Handler.class));
 
         mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
-                TEST_ARG2);
+                TEST_ARG2, TEST_OBJ);
     }
 
     /**
@@ -114,6 +115,7 @@
         assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
         assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
         assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
+        assertEquals("obj", TEST_OBJ, mHandler.getLastMessage().obj);
     }
 
     /**
diff --git a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
index 23e375d..83f2763 100644
--- a/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
@@ -106,7 +106,6 @@
     <string name="close" msgid="3043722427445528732">"Zatvori"</string>
     <string name="copy_failure_alert_content" msgid="4563147454522476183">"Sledeće datoteke nisu kopirane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="2635075788682922861">"Sledeće datoteke nisu premeštene: <xliff:g id="LIST">%1$s</xliff:g>"</string>
-    <string name="delete_failure_alert_content" msgid="892393767207938353">"Sledeće datoteke nisu izbrisane: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su konvertovane u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
       <item quantity="one">Kopirali ste <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku u privremenu memoriju.</item>
@@ -150,6 +149,4 @@
       <item quantity="few">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
       <item quantity="other">Želite li da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
     </plurals>
-    <string name="too_many_selected" msgid="6781456208116966753">"Žao nam je, istovremeno možete da izaberete najviše 1000 stavki"</string>
-    <string name="too_many_in_select_all" msgid="8281987479885307456">"Možete da izaberete najviše 1000 stavki"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-be-rBY/strings.xml b/packages/DocumentsUI/res/values-be-rBY/strings.xml
index fabcdc2..1c06cd1 100644
--- a/packages/DocumentsUI/res/values-be-rBY/strings.xml
+++ b/packages/DocumentsUI/res/values-be-rBY/strings.xml
@@ -46,14 +46,14 @@
     <string name="button_dismiss" msgid="3714065566893946085">"Адхіліць"</string>
     <string name="button_retry" msgid="4392027584153752797">"Паўтарыце спробу"</string>
     <string name="sort_name" msgid="9183560467917256779">"Па назве"</string>
-    <string name="sort_date" msgid="586080032956151448">"Па даце змянення"</string>
+    <string name="sort_date" msgid="586080032956151448">"Па даце ўнясення змен"</string>
     <string name="sort_size" msgid="3350681319735474741">"Па памеры"</string>
     <string name="drawer_open" msgid="4545466532430226949">"Паказаць каранёвыя папкі"</string>
     <string name="drawer_close" msgid="7602734368552123318">"Схаваць каранёвыя папкі"</string>
     <string name="save_error" msgid="6167009778003223664">"Не атрымалася захаваць дакумент"</string>
     <string name="create_error" msgid="3735649141335444215">"Не атрымалася стварыць папку"</string>
     <string name="query_error" msgid="5999895349602476581">"Зараз немагчыма загрузіць змесціва"</string>
-    <string name="root_recent" msgid="4470053704320518133">"Нядаўнія"</string>
+    <string name="root_recent" msgid="4470053704320518133">"Апошнія"</string>
     <string name="root_available_bytes" msgid="8568452858617033281">"<xliff:g id="SIZE">%1$s</xliff:g> свабодна"</string>
     <string name="root_type_service" msgid="2178854894416775409">"Службы захоўвання"</string>
     <string name="root_type_shortcut" msgid="3318760609471618093">"Ярлыкі"</string>
@@ -112,7 +112,6 @@
     <string name="close" msgid="3043722427445528732">"Закрыць"</string>
     <string name="copy_failure_alert_content" msgid="4563147454522476183">"Не былі скапіраваны наступныя файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="2635075788682922861">"Не былі перамешчаны наступныя файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
-    <string name="delete_failure_alert_content" msgid="892393767207938353">"Не былі выдалены наступныя файлы: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="copy_converted_warning_content" msgid="5753861488218674361">"Гэтыя файлы былі сканвертаваныя ў іншы фармат: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
       <item quantity="one">У буфер абмену скапіраваны <xliff:g id="COUNT_1">%1$d</xliff:g> файл.</item>
@@ -129,7 +128,7 @@
     <string name="open_external_dialog_root_request" msgid="8899108702926347720">"Даць <xliff:g id="APPNAME"><b>^1</b></xliff:g> доступ да вашых даных, у тым ліку фатаграфій і відэа, на <xliff:g id="STORAGE"><i>^2</i></xliff:g>?"</string>
     <string name="never_ask_again" msgid="4295278542972859268">"Больш не пытацца"</string>
     <string name="allow" msgid="7225948811296386551">"Дазволіць"</string>
-    <string name="deny" msgid="2081879885755434506">"Адмовіць"</string>
+    <string name="deny" msgid="2081879885755434506">"Забараніць"</string>
     <plurals name="elements_selected" formatted="false" msgid="1376955402452875047">
       <item quantity="one">Выбраны <xliff:g id="COUNT_1">%1$d</xliff:g></item>
       <item quantity="few">Выбраны <xliff:g id="COUNT_1">%1$d</xliff:g></item>
@@ -162,6 +161,4 @@
       <item quantity="many">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элементаў?</item>
       <item quantity="other">Выдаліць <xliff:g id="COUNT_1">%1$d</xliff:g> элемента?</item>
     </plurals>
-    <string name="too_many_selected" msgid="6781456208116966753">"На жаль, вы можаце выбраць не больш за 1000 элементаў адначасова"</string>
-    <string name="too_many_in_select_all" msgid="8281987479885307456">"Атрымалася выбраць толькі 1000 элементаў"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-bs-rBA/strings.xml b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
index eff27449..aae7986 100644
--- a/packages/DocumentsUI/res/values-bs-rBA/strings.xml
+++ b/packages/DocumentsUI/res/values-bs-rBA/strings.xml
@@ -106,7 +106,6 @@
     <string name="close" msgid="3043722427445528732">"Zatvori"</string>
     <string name="copy_failure_alert_content" msgid="4563147454522476183">"Nisu kopirani sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="2635075788682922861">"Nisu premješteni sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
-    <string name="delete_failure_alert_content" msgid="892393767207938353">"Nisu izbrisani sljedeći fajlovi: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="copy_converted_warning_content" msgid="5753861488218674361">"Ove datoteke su pretvorene u drugi format: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> fajl je kopiran u međuspremnik.</item>
@@ -150,6 +149,4 @@
       <item quantity="few">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavke?</item>
       <item quantity="other">Želite li izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> stavki?</item>
     </plurals>
-    <string name="too_many_selected" msgid="6781456208116966753">"Žao nam je, možete izabrati samo do 1000 stavki istovremeno"</string>
-    <string name="too_many_in_select_all" msgid="8281987479885307456">"Možete izabrati samo 1000 stavki"</string>
 </resources>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 971afdc..21cf755 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -53,7 +53,7 @@
     <string name="save_error" msgid="6167009778003223664">"無法儲存文件"</string>
     <string name="create_error" msgid="3735649141335444215">"無法建立資料夾"</string>
     <string name="query_error" msgid="5999895349602476581">"目前無法載入內容"</string>
-    <string name="root_recent" msgid="4470053704320518133">"最近"</string>
+    <string name="root_recent" msgid="4470053704320518133">"近期用過"</string>
     <string name="root_available_bytes" msgid="8568452858617033281">"可用空間:<xliff:g id="SIZE">%1$s</xliff:g>"</string>
     <string name="root_type_service" msgid="2178854894416775409">"儲存空間服務"</string>
     <string name="root_type_shortcut" msgid="3318760609471618093">"捷徑"</string>
diff --git a/packages/InputDevices/res/values-be-rBY/strings.xml b/packages/InputDevices/res/values-be-rBY/strings.xml
index a552fa5..7d7683c 100644
--- a/packages/InputDevices/res/values-be-rBY/strings.xml
+++ b/packages/InputDevices/res/values-be-rBY/strings.xml
@@ -3,8 +3,8 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="8016145283189546017">"Input Devices"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Клавіятура Android"</string>
-    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"англійская (Вялікабрытанія)"</string>
-    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"англійская (ЗША)"</string>
+    <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Англійская (Злучанае Каралеўства)"</string>
+    <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Англійская (ЗША)"</string>
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Англійская (ЗША), міжнар. раскладка"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Англійская (ЗША), раскладка Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Англійская (ЗША), раскладка Дворака"</string>
diff --git a/packages/Keyguard/res/values-b+sr+Latn/strings.xml b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
index 22dc059..70f3bda 100644
--- a/packages/Keyguard/res/values-b+sr+Latn/strings.xml
+++ b/packages/Keyguard/res/values-b+sr+Latn/strings.xml
@@ -121,8 +121,10 @@
     <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Treba da unesete šablon kada prelazite sa jednog profila na drugi"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Treba da unesete PIN kada prelazite sa jednog profila na drugi"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Treba da unesete lozinku kada prelazite sa jednog profila na drugi"</string>
-    <string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"Administrator uređaja je zaključao uređaj"</string>
-    <string name="kg_prompt_reason_user_request" msgid="500999297306031595">"Uređaj je ručno zaključan"</string>
+    <!-- no translation found for kg_prompt_reason_device_admin (5838877342219587193) -->
+    <skip />
+    <!-- no translation found for kg_prompt_reason_user_request (500999297306031595) -->
+    <skip />
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite šablon.</item>
       <item quantity="few">Niste otključali uređaj <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite šablon.</item>
diff --git a/packages/Keyguard/res/values-be-rBY/strings.xml b/packages/Keyguard/res/values-be-rBY/strings.xml
index ca6a476..4ed1a10 100644
--- a/packages/Keyguard/res/values-be-rBY/strings.xml
+++ b/packages/Keyguard/res/values-be-rBY/strings.xml
@@ -58,7 +58,7 @@
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Выдаліць"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
     <string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"Забылі ключ"</string>
-    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільны ўзор"</string>
+    <string name="kg_wrong_pattern" msgid="1850806070801358830">"Няправільна ключ"</string>
     <string name="kg_wrong_password" msgid="2333281762128113157">"Няправiльны пароль"</string>
     <string name="kg_wrong_pin" msgid="1131306510833563801">"Няправільны PIN-код"</string>
     <string name="kg_too_many_failed_attempts_countdown" msgid="6358110221603297548">"Паўтарыце спробу праз <xliff:g id="NUMBER">%d</xliff:g> с."</string>
@@ -123,8 +123,10 @@
     <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Пры пераключэнні профіляў патрабуецца ўзор"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Пры пераключэнні профіляў патрабуецца PIN-код"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Пры пераключэнні профіляў патрабуецца пароль"</string>
-    <string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"Адміністратар прылады заблакіраваў прыладу"</string>
-    <string name="kg_prompt_reason_user_request" msgid="500999297306031595">"Прылада была заблакіравана ўручную"</string>
+    <!-- no translation found for kg_prompt_reason_device_admin (5838877342219587193) -->
+    <skip />
+    <!-- no translation found for kg_prompt_reason_user_request (500999297306031595) -->
+    <skip />
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзіны. Увядзіце ўзор.</item>
       <item quantity="few">Прылада не была разблакіравана на працягу <xliff:g id="NUMBER_1">%d</xliff:g> гадзін. Увядзіце ўзор.</item>
diff --git a/packages/Keyguard/res/values-bs-rBA/strings.xml b/packages/Keyguard/res/values-bs-rBA/strings.xml
index be73580..062213e 100644
--- a/packages/Keyguard/res/values-bs-rBA/strings.xml
+++ b/packages/Keyguard/res/values-bs-rBA/strings.xml
@@ -121,8 +121,10 @@
     <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Potreban je uzorak nakon prelaska na drugi profil"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Potreban je PIN nakon prelaska na drugi profil"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Potrebna je lozinka nakon prelaska na drugi profil"</string>
-    <string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"Administrator je zaključao uređaj."</string>
-    <string name="kg_prompt_reason_user_request" msgid="500999297306031595">"Uređaj je ručno zaključan"</string>
+    <!-- no translation found for kg_prompt_reason_device_admin (5838877342219587193) -->
+    <skip />
+    <!-- no translation found for kg_prompt_reason_user_request (500999297306031595) -->
+    <skip />
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
       <item quantity="one">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sat. Potvrdite obrazac.</item>
       <item quantity="few">Uređaj nije bio otključan <xliff:g id="NUMBER_1">%d</xliff:g> sata. Potvrdite obrazac.</item>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index 9bc2456..7259bd3 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -110,20 +110,20 @@
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
     <string name="accessibility_ime_switch_button" msgid="2829803408288433429">"Changer de méthode d\'entrée"</string>
     <string name="airplane_mode" msgid="3122107900897202805">"Mode Avion"</string>
-    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Le schéma est exigé après le redémarrage de l\'appareil"</string>
+    <string name="kg_prompt_reason_restart_pattern" msgid="5519822969283306009">"Le motif est exigé après le redémarrage de l\'appareil"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="4411398237158448198">"Le NIP est exigé après le redémarrage de l\'appareil"</string>
     <string name="kg_prompt_reason_restart_password" msgid="6504585392626524695">"Le mot de passe est exigé après le redémarrage de l\'appareil"</string>
-    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Le schéma est exigé pour plus de sécurité"</string>
+    <string name="kg_prompt_reason_timeout_pattern" msgid="3717506169674397620">"Le motif est exigé pour plus de sécurité"</string>
     <string name="kg_prompt_reason_timeout_pin" msgid="6951483704195396341">"Le NIP est exigé pour plus de sécurité"</string>
     <string name="kg_prompt_reason_timeout_password" msgid="7306667546971345027">"Le mot de passe est exigé pour plus de sécurité"</string>
-    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Le schéma est exigé lorsque vous changez de profil"</string>
+    <string name="kg_prompt_reason_switch_profiles_pattern" msgid="8476293962695171574">"Le motif est exigé lorsque vous changez de profil"</string>
     <string name="kg_prompt_reason_switch_profiles_pin" msgid="2343607138520460043">"Le NIP est exigé lorsque vous changez de profil"</string>
     <string name="kg_prompt_reason_switch_profiles_password" msgid="1295960907951965927">"Le mot de passe est exigé lorsque vous changez de profil"</string>
     <string name="kg_prompt_reason_device_admin" msgid="5838877342219587193">"L\'administrateur de l\'appareil l\'a verrouillé"</string>
     <string name="kg_prompt_reason_user_request" msgid="500999297306031595">"L\'appareil a été verrouillé manuellement"</string>
     <plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="2697444392228541853">
-      <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le schéma.</item>
-      <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le schéma.</item>
+      <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le motif.</item>
+      <item quantity="other">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heures. Confirmez le motif.</item>
     </plurals>
     <plurals name="kg_prompt_reason_time_pin" formatted="false" msgid="2118758475374354849">
       <item quantity="one">L\'appareil n\'a pas été déverrouillé depuis <xliff:g id="NUMBER_1">%d</xliff:g> heure. Confirmez le NIP.</item>
diff --git a/packages/Keyguard/res/values-pa-rIN/strings.xml b/packages/Keyguard/res/values-pa-rIN/strings.xml
index 8cf86a0..5f0b6d8 100644
--- a/packages/Keyguard/res/values-pa-rIN/strings.xml
+++ b/packages/Keyguard/res/values-pa-rIN/strings.xml
@@ -25,7 +25,7 @@
     <string name="keyguard_password_enter_puk_code" msgid="3035856550289724338">"SIM PUK ਅਤੇ ਨਵਾਂ PIN ਕੋਡ ਟਾਈਪ ਕਰੋ"</string>
     <string name="keyguard_password_enter_puk_prompt" msgid="1801941051094974609">"SIM PUK ਕੋਡ"</string>
     <string name="keyguard_password_enter_pin_prompt" msgid="3201151840570492538">"ਨਵਾਂ SIM PIN ਕੋਡ"</string>
-    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ਪਾਸਵਰਡ ਟਾਈਪ ਕਰਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ"</font></string>
+    <string name="keyguard_password_entry_touch_hint" msgid="7858547464982981384"><font size="17">"ਪਾਸਵਰਡ ਟਾਈਪ ਕਰਨ ਲਈ ਛੋਹਵੋ"</font></string>
     <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"ਅਨਲੌਕ ਕਰਨ ਲਈ ਪਾਸਵਰਡ ਟਾਈਪ ਕਰੋ"</string>
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"ਅਨਲੌਕ ਕਰਨ ਲਈ PIN ਟਾਈਪ ਕਰੋ"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"ਗ਼ਲਤ PIN ਕੋਡ।"</string>
diff --git a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
index c2b84d0..50ce1f9 100644
--- a/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
+++ b/packages/PrintSpooler/res/values-b+sr+Latn/strings.xml
@@ -62,7 +62,6 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Još informacija o ovom štampaču"</string>
-    <string name="could_not_create_file" msgid="3425025039427448443">"Pravljenje datoteke nije uspelo"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge štampanja su onemogućene"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Pretraga štampača"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Nijedna usluga štampanja nije omogućena"</string>
diff --git a/packages/PrintSpooler/res/values-be-rBY/strings.xml b/packages/PrintSpooler/res/values-be-rBY/strings.xml
index e74b4cf..c264f92 100644
--- a/packages/PrintSpooler/res/values-be-rBY/strings.xml
+++ b/packages/PrintSpooler/res/values-be-rBY/strings.xml
@@ -63,7 +63,6 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> – <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Больш падрабязная інфармацыя пра гэты прынтар"</string>
-    <string name="could_not_create_file" msgid="3425025039427448443">"Не ўдалося стварыць файл"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"Некаторыя службы друку адключаны"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Пошук прынтараў"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Службы друку не ўключаны"</string>
diff --git a/packages/PrintSpooler/res/values-bs-rBA/strings.xml b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
index cc04d66..c3c9bb33 100644
--- a/packages/PrintSpooler/res/values-bs-rBA/strings.xml
+++ b/packages/PrintSpooler/res/values-bs-rBA/strings.xml
@@ -62,7 +62,6 @@
     </plurals>
     <string name="printer_extended_description_template" msgid="1366699227703381874">"<xliff:g id="PRINT_SERVICE_LABEL">%1$s</xliff:g> - <xliff:g id="PRINTER_DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="printer_info_desc" msgid="7181988788991581654">"Više informacija o ovom štampaču"</string>
-    <string name="could_not_create_file" msgid="3425025039427448443">"Nije uspjelo kreiranje fajla"</string>
     <string name="print_services_disabled_toast" msgid="9089060734685174685">"Neke usluge za štampanje su isključene"</string>
     <string name="print_searching_for_printers" msgid="6550424555079932867">"Traženje štampača"</string>
     <string name="print_no_print_services" msgid="8561247706423327966">"Usluga za štampanje nije uključena"</string>
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
deleted file mode 100644
index 6e29d23..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
deleted file mode 100644
index 6110e9e..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
deleted file mode 100644
index 6cca225..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
deleted file mode 100644
index 6445f2a..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
deleted file mode 100644
index 78c0294..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
deleted file mode 100644
index 2fcc3b0..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
deleted file mode 100644
index 70d35bf..0000000
--- a/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
deleted file mode 100644
index 2d9b75e..0000000
--- a/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
deleted file mode 100644
index b6ebe34..0000000
--- a/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
deleted file mode 100644
index 8b67b91..0000000
--- a/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
deleted file mode 100644
index 1fa0a3d..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
deleted file mode 100644
index 175bd78..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
deleted file mode 100644
index 05b27e8..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
deleted file mode 100644
index 6e9f8ae..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
deleted file mode 100644
index 5f3371f..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
deleted file mode 100644
index 539d77f..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
deleted file mode 100644
index 3216776..0000000
--- a/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
deleted file mode 100644
index 4f381ba..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
deleted file mode 100644
index c67127d..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
deleted file mode 100644
index d3b356b..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
deleted file mode 100644
index 2d38129..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
deleted file mode 100644
index fb76575..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
deleted file mode 100644
index d8b68eb..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
deleted file mode 100644
index 02cc3af..0000000
--- a/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
deleted file mode 100644
index 7805b7a..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
deleted file mode 100644
index 8127774..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
deleted file mode 100644
index 84b8085..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
deleted file mode 100644
index 289d6ac..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
deleted file mode 100644
index 72bc804..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
deleted file mode 100644
index e31ce2b..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
deleted file mode 100644
index f23b0e7..0000000
--- a/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
deleted file mode 100644
index 1e12f96..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
deleted file mode 100644
index 8b547d9..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
deleted file mode 100644
index 03c5033..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
deleted file mode 100644
index b9a9923..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
deleted file mode 100644
index 989e1ab..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
deleted file mode 100644
index de8c389..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
deleted file mode 100644
index 2eb8a92..0000000
--- a/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SettingsLib/res/drawable/ic_bt_cellphone.xml b/packages/SettingsLib/res/drawable/ic_bt_cellphone.xml
new file mode 100644
index 0000000..cc9b732
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_cellphone.xml
@@ -0,0 +1,29 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent"
+    android:autoMirrored="true">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M6.62,10.79c1.44,2.83 3.76,5.14 6.59,6.59l2.2,-2.2c0.27,-0.27 0.67,-0.36
+            1.02,-0.24 1.12,0.37 2.33,0.57 3.57,0.57 0.55,0 1,0.45 1,1V20c0,0.55 -0.45,1 -1,1
+            -9.39,0 -17,-7.61 -17,-17 0,-0.55 0.45,-1 1,-1h3.5c0.55,0 1,0.45 1,1 0,1.25 0.2,2.45
+            0.57,3.57 0.11,0.35 0.03,0.74 -0.25,1.02l-2.2,2.2z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml b/packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml
new file mode 100644
index 0000000..bbe3914
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_headphones_a2dp.xml
@@ -0,0 +1,26 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87
+            3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml b/packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml
new file mode 100644
index 0000000..ceeef19
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_headset_hfp.xml
@@ -0,0 +1,27 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87
+            3.13,-7 7,-7s7,3.13 7,7v2h-4v8h4v1h-7v2h6c1.66,0 3,-1.34 3,-3V10c0,-4.97 -4.03,-9
+            -9,-9z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml b/packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml
new file mode 100644
index 0000000..67b42ae
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_misc_hid.xml
@@ -0,0 +1,26 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M15,7.5V2H9v5.5l3,3 3,-3zM7.5,9H2v6h5.5l3,-3 -3,-3zM9,16.5V22h6v-5.5l-3,-3
+            -3,3zM16.5,9l-3,3 3,3H22V9h-5.5z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_bt_network_pan.xml b/packages/SettingsLib/res/drawable/ic_bt_network_pan.xml
new file mode 100644
index 0000000..c5ab01c
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_network_pan.xml
@@ -0,0 +1,30 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M14.24,12.01l2.32,2.32c0.28,-0.72 0.44,-1.51 0.44,-2.33 0,-0.82
+            -0.16,-1.59 -0.43,-2.31l-2.33,2.32zM19.53,6.71l-1.26,1.26c0.63,1.21 0.98,2.57
+            0.98,4.02s-0.36,2.82 -0.98,4.02l1.2,1.2c0.97,-1.54 1.54,-3.36 1.54,-5.31 -0.01,-1.89
+            -0.55,-3.67 -1.48,-5.19zM15.71,7.71L10,2L9,2v7.59L4.41,5 3,6.41 8.59,12 3,17.59 4.41,19
+            9,14.41L9,22h1l5.71,-5.71 -4.3,-4.29
+            4.3,-4.29zM11,5.83l1.88,1.88L11,9.59L11,5.83zM12.88,16.29L11,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml b/packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml
new file mode 100644
index 0000000..821618d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_bt_pointing_hid.xml
@@ -0,0 +1,26 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M13,1.07L13,9h7c0,-4.08 -3.05,-7.44 -7,-7.93zM4,15c0,4.42
+            3.58,8 8,8s8,-3.58 8,-8v-4L4,11v4zM11,1.07C7.05,1.56 4,4.92 4,9h7L11,1.07z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml b/packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml
new file mode 100644
index 0000000..4aa8569
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_lockscreen_ime.xml
@@ -0,0 +1,26 @@
+<!--
+     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.0"
+    android:viewportHeight="24.0"
+    android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M20,5L4,5c-1.1,0 -1.99,0.9 -1.99,2L2,17c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9
+            2,-2L22,7c0,-1.1 -0.9,-2 -2,-2zM11,8h2v2h-2L11,8zM11,11h2v2h-2v-2zM8,8h2v2L8,10L8,8zM8,11h2v2L8,13v-2zM7,13L5,13v-2h2v2zM7,10L5,10L5,8h2v2zM16,17L8,17v-2h8v2zM16,13h-2v-2h2v2zM16,10h-2L14,8h2v2zM19,13h-2v-2h2v2zM19,10h-2L17,8h2v2z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index 67296a6..a68a44e 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -41,6 +41,11 @@
                 android:background="?android:attr/colorPrimary" />
         </FrameLayout>
         <FrameLayout
+            android:id="@+id/content_header_container"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="?android:attr/actionBarStyle" />
+        <FrameLayout
             android:id="@+id/content_frame"
             android:layout_width="match_parent"
             android:layout_height="fill_parent"
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index a61462d..e8621b2 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -91,7 +91,7 @@
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth privezivanje"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Povezivanje sa internetom"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"Povezivanje i prenosni hotspot"</string>
-    <string name="managed_user_title" msgid="8109605045406748842">"Sve radne aplikacije"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil za posao"</string>
     <string name="user_guest" msgid="8475274842845401871">"Gost"</string>
     <string name="unknown" msgid="1592123443519355854">"Nepoznato"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Korisnik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -123,8 +123,6 @@
     <string name="tts_engine_settings_button" msgid="1030512042040722285">"Pokreni podešavanja mašine"</string>
     <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Željena mašina"</string>
     <string name="tts_general_section_title" msgid="4402572014604490502">"Opšte"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Resetujte visinu tona govora"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Resetujte visinu tona kojom se tekst izgovara na podrazumevanu."</string>
   <string-array name="tts_rate_entries">
     <item msgid="6695494874362656215">"Veoma sporo"</item>
     <item msgid="4795095314303559268">"Sporo"</item>
@@ -167,6 +165,7 @@
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogući detaljniju evidenciju za Wi‑Fi"</string>
     <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agresivan prelaz sa Wi‑Fi mreže na mobilnu"</string>
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvek dozvoli skeniranje Wi‑Fi-ja u romingu"</string>
+    <string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Podaci za mobilne uređaje su uvek aktivni"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogući glavno podešavanje jačine zvuka"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Prikaz opcija za sertifikaciju bežičnog ekrana"</string>
@@ -275,8 +274,8 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivna. Dodirnite da biste je deaktivirali."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Prikaz i kontrola trenutno pokrenutih usluga"</string>
-    <string name="enable_webview_multiprocess" msgid="3352660896640797330">"Višeprocesni WebView"</string>
-    <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Pokrećite WebView prikazivače zasebno"</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogući višeprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrećite WebView prikazivače u okviru izolovanog procesa."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Primena WebView-a"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesite primenu WebView-a"</string>
     <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više nije važeći. Pokušajte ponovo."</string>
@@ -324,11 +323,6 @@
     <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio je administrator"</string>
     <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
     <string name="home" msgid="3256884684164448244">"Početna za Podešavanja"</string>
-  <string-array name="battery_labels">
-    <item msgid="8494684293649631252">"0%"</item>
-    <item msgid="8934126114226089439">"50%"</item>
-    <item msgid="1286113608943010849">"100%"</item>
-  </string-array>
     <string name="charge_length_format" msgid="8978516217024434156">"Pre <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Još <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Mali"</string>
diff --git a/packages/SettingsLib/res/values-be-rBY/arrays.xml b/packages/SettingsLib/res/values-be-rBY/arrays.xml
index 9ac862b7..63b8b9b 100644
--- a/packages/SettingsLib/res/values-be-rBY/arrays.xml
+++ b/packages/SettingsLib/res/values-be-rBY/arrays.xml
@@ -128,12 +128,12 @@
     <item msgid="1340692776955662664">"Выклікаць стэк на glGetError"</item>
   </string-array>
   <string-array name="show_non_rect_clip_entries">
-    <item msgid="993742912147090253">"Выключана"</item>
+    <item msgid="993742912147090253">"Адключана"</item>
     <item msgid="675719912558941285">"Намаляваць непрамавугольную вобласць кліпа сінім колерам"</item>
     <item msgid="1064373276095698656">"Вылучыце выпрабаваныя каманды малявання зялёным колерам"</item>
   </string-array>
   <string-array name="track_frame_time_entries">
-    <item msgid="2193584639058893150">"Выключана"</item>
+    <item msgid="2193584639058893150">"Адключана"</item>
     <item msgid="2751513398307949636">"На экране ў выглядзе слупкоў"</item>
     <item msgid="1851438178120770973">"У абалонцы adb dumpsys gfxinfo"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-be-rBY/strings.xml b/packages/SettingsLib/res/values-be-rBY/strings.xml
index 5d4d688..a8abb49 100644
--- a/packages/SettingsLib/res/values-be-rBY/strings.xml
+++ b/packages/SettingsLib/res/values-be-rBY/strings.xml
@@ -23,7 +23,7 @@
     <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не атрымлiваецца выканаць сканаванне для сетак"</string>
     <string name="wifi_security_none" msgid="7985461072596594400">"Няма"</string>
     <string name="wifi_remembered" msgid="4955746899347821096">"Захавана"</string>
-    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Адключана"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Адключаная"</string>
     <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Збой канфігурацыі IP"</string>
     <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Збой падлучэння Wi-Fi"</string>
     <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Праблема аўтэнтыфікацыі"</string>
@@ -71,7 +71,7 @@
     <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Выкарыстоўваць для ўводу"</string>
     <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Падлучыць"</string>
     <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"СПАЛУЧЫЦЬ"</string>
-    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Скасаваць"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Адмена"</string>
     <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Спалучэнне дае доступ да вашых кантактаў і гісторыі выклікаў пры падлучэнні."</string>
     <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Не атрымалася падключыцца да прылады <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
     <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Не атрымалася спалучыцца з прыладай <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, таму што PIN-код або пароль няправiльныя."</string>
@@ -91,14 +91,14 @@
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-мадэм"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Мадэм"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"Мадэм і партатыўны хотспот"</string>
-    <string name="managed_user_title" msgid="8109605045406748842">"Усе працоўныя праграмы"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Рабочы профіль"</string>
     <string name="user_guest" msgid="8475274842845401871">"Госць"</string>
     <string name="unknown" msgid="1592123443519355854">"Невядома"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Карыстальнiк: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="313159469856372621">"Некат. параметры па змаўч. усталяваныя"</string>
     <string name="launch_defaults_none" msgid="4241129108140034876">"Параметры па змаўчанні не ўсталяваныя"</string>
     <string name="tts_settings" msgid="8186971894801348327">"Налады Text-to-speech"</string>
-    <string name="tts_settings_title" msgid="1237820681016639683">"Сінтэз маўлення"</string>
+    <string name="tts_settings_title" msgid="1237820681016639683">"Выводзіць праз Text-to-speech"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Хуткасць гаворкі"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Хуткасць, з якой кажуць тэкст"</string>
     <string name="tts_default_pitch_title" msgid="6135942113172488671">"Тон"</string>
@@ -123,8 +123,6 @@
     <string name="tts_engine_settings_button" msgid="1030512042040722285">"Запуск налад модулю"</string>
     <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Выбраны модуль"</string>
     <string name="tts_general_section_title" msgid="4402572014604490502">"Агульныя"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Скід вышыні голасу падчас маўлення"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Скінуць вышыню голасу, з якой прагаворваецца тэкст, да стандартнай."</string>
   <string-array name="tts_rate_entries">
     <item msgid="6695494874362656215">"Вельмі павольна"</item>
     <item msgid="4795095314303559268">"Павольна"</item>
@@ -139,7 +137,7 @@
     <string name="choose_profile" msgid="8229363046053568878">"Выбраць профіль"</string>
     <string name="category_personal" msgid="1299663247844969448">"Асабісты"</string>
     <string name="category_work" msgid="8699184680584175622">"Рабочы"</string>
-    <string name="development_settings_title" msgid="215179176067683667">"Параметры распрацоўшчыка"</string>
+    <string name="development_settings_title" msgid="215179176067683667">"Опцыі распрацоўшчыка"</string>
     <string name="development_settings_enable" msgid="542530994778109538">"Уключыць параметры распрацоўшчыка"</string>
     <string name="development_settings_summary" msgid="1815795401632854041">"Налада параметраў для распрацоўкі прыкладанняў"</string>
     <string name="development_settings_not_available" msgid="4308569041701535607">"Параметры распрацоўшчыка недаступныя для гэтага карыстальніка"</string>
@@ -167,6 +165,7 @@
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Уключыць падрабязны журнал Wi‑Fi"</string>
     <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Агрэсіўны пераход з Wi‑Fi на маб. сетку"</string>
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Заўсёды дазваляць роўмінгавае сканіраванне Wi‑Fi"</string>
+    <string name="legacy_dhcp_client" msgid="694426978909127287">"Выкарыстоўваць кліент DHCP ранейшых версій"</string>
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Перадача даных мабільнай сувязі заўсёды актыўна"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Адключыць абсалютны гук"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Паказаць опцыі сертыфікацыі бесправаднога дысплея"</string>
@@ -226,7 +225,7 @@
     <string name="enable_opengl_traces_title" msgid="6790444011053219871">"Уключэнне слядоў OpenGL"</string>
     <string name="usb_audio_disable_routing" msgid="8114498436003102671">"Адключыць аўдыёмаршрутызацыю USB"</string>
     <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"Адкл. аўт. перанакір. на перыфер. USB-прыл. аўдыё"</string>
-    <string name="debug_layout" msgid="5981361776594526155">"Паказаць межы макета"</string>
+    <string name="debug_layout" msgid="5981361776594526155">"Паказаць межы размяшчэння"</string>
     <string name="debug_layout_summary" msgid="2001775315258637682">"Паказаць межы кліпу, палі і г. д."</string>
     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"Прымусовая раскладка справа налева"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"Прымусовая раскладка экрана справа налева для ўсіх рэгіянальных налад"</string>
@@ -237,12 +236,12 @@
     <string name="force_msaa" msgid="7920323238677284387">"Прымусовае выкананне 4x MSAA"</string>
     <string name="force_msaa_summary" msgid="9123553203895817537">"Уключыць 4x MSAA у прыкладаннях з OpenGL ES 2.0"</string>
     <string name="show_non_rect_clip" msgid="505954950474595172">"Адладка аперацый непрамавугольнага кліпа"</string>
-    <string name="track_frame_time" msgid="6146354853663863443">"Профіль рэндэрынгу GPU"</string>
+    <string name="track_frame_time" msgid="6146354853663863443">"Апрацоўка профілю GPU"</string>
     <string name="window_animation_scale_title" msgid="6162587588166114700">"Маштаб анімацыі акна"</string>
     <string name="transition_animation_scale_title" msgid="387527540523595875">"Маштаб перадачы анімацыі"</string>
     <string name="animator_duration_scale_title" msgid="3406722410819934083">"Шкала працягласці анiматара"</string>
     <string name="overlay_display_devices_title" msgid="5364176287998398539">"Мадэляванне другасных дысплеяў"</string>
-    <string name="debug_applications_category" msgid="4206913653849771549">"Праграмы"</string>
+    <string name="debug_applications_category" msgid="4206913653849771549">"Прыкладаннi"</string>
     <string name="immediately_destroy_activities" msgid="1579659389568133959">"Не захоўваць дзеянні"</string>
     <string name="immediately_destroy_activities_summary" msgid="3592221124808773368">"Знішч. кож.дзеянне, як толькі карыст.пакідае яго"</string>
     <string name="app_process_limit_title" msgid="4280600650253107163">"Ліміт фонавага працэсу"</string>
@@ -275,8 +274,8 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Актыўная. Краніце, каб пераключыць."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Запушчаныя службы"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Прагляд запушчаных службаў i кіраванне iмi"</string>
-    <string name="enable_webview_multiprocess" msgid="3352660896640797330">"Шматпрацэсны WebView"</string>
-    <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Запусціць апрацоўшчыкі WebView асобна"</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Уключыць шматпрацэсны WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Запусціць апрацоўшчыкі WebView у ізаляваным працэсе."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Рэалізацыя WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Наладзіць рэалізацыю WebView"</string>
     <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Гэты варыянт больш не даступны. Паспрабуйце яшчэ раз."</string>
@@ -324,11 +323,6 @@
     <string name="enabled_by_admin" msgid="2386503803463071894">"Уключана адміністратарам"</string>
     <string name="disabled_by_admin" msgid="3669999613095206948">"Адключана адміністратарам"</string>
     <string name="home" msgid="3256884684164448244">"Галоўная старонка налад"</string>
-  <string-array name="battery_labels">
-    <item msgid="8494684293649631252">"0 %"</item>
-    <item msgid="8934126114226089439">"50 %"</item>
-    <item msgid="1286113608943010849">"100 %"</item>
-  </string-array>
     <string name="charge_length_format" msgid="8978516217024434156">"<xliff:g id="ID_1">%1$s</xliff:g> таму назад"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Засталося <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Маленькі"</string>
diff --git a/packages/SettingsLib/res/values-bs-rBA/strings.xml b/packages/SettingsLib/res/values-bs-rBA/strings.xml
index 28e3507..9589b62 100644
--- a/packages/SettingsLib/res/values-bs-rBA/strings.xml
+++ b/packages/SettingsLib/res/values-bs-rBA/strings.xml
@@ -91,7 +91,7 @@
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetooth veze"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Dijeljenje veze"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"Dijeljenje internetske veze i prijenosna pristupna tačka"</string>
-    <string name="managed_user_title" msgid="8109605045406748842">"Sve radne aplikacije"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil za Work"</string>
     <string name="user_guest" msgid="8475274842845401871">"Gost"</string>
     <string name="unknown" msgid="1592123443519355854">"Nepoznato"</string>
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Korisnik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
@@ -123,8 +123,6 @@
     <string name="tts_engine_settings_button" msgid="1030512042040722285">"Pokreni postavke programa"</string>
     <string name="tts_engine_preference_section_title" msgid="448294500990971413">"Željeni program"</string>
     <string name="tts_general_section_title" msgid="4402572014604490502">"Opće"</string>
-    <string name="tts_reset_speech_pitch_title" msgid="5789394019544785915">"Postavite visinu glasa"</string>
-    <string name="tts_reset_speech_pitch_summary" msgid="8700539616245004418">"Visinu glasa koji izgovara tekst postavite na podrazumjevanu."</string>
   <string-array name="tts_rate_entries">
     <item msgid="6695494874362656215">"Veoma sporo"</item>
     <item msgid="4795095314303559268">"Sporo"</item>
@@ -167,6 +165,7 @@
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Omogućiti Wi-Fi Verbose zapisivanje"</string>
     <string name="wifi_aggressive_handover" msgid="9194078645887480917">"Agresivni Wi-Fi u mobilnoj primopredaji"</string>
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Uvijek dopustiti Wi-Fi lutajuće skeniranje"</string>
+    <string name="legacy_dhcp_client" msgid="694426978909127287">"Koristi zastareli DHCP klijent"</string>
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Mobilni podaci uvijek aktivni"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Onemogućite apsolutnu jačinu zvuka"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Pokaži opcije za certifikaciju Bežičnog prikaza"</string>
@@ -275,8 +274,8 @@
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"Aktivno. Dodirnite za promjenu opcije."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"Pokrenute usluge"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"Prikažite trenutno pokrenute usluge i upravljajte njima"</string>
-    <string name="enable_webview_multiprocess" msgid="3352660896640797330">"Višeprocesni WebView"</string>
-    <string name="enable_webview_multiprocess_desc" msgid="2485604010404197724">"Pokreni odvojeno WebView rendere"</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"Omogućiti višeprocesni WebView"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Pokrenite WebView operatera u izolovanom procesu."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Postavljanje WebViewa"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Podesi WebView"</string>
     <string name="select_webview_provider_toast_text" msgid="5466970498308266359">"Ovaj izbor više ne vrijedi. Pokušajte ponovo."</string>
@@ -324,11 +323,6 @@
     <string name="enabled_by_admin" msgid="2386503803463071894">"Omogućio administrator"</string>
     <string name="disabled_by_admin" msgid="3669999613095206948">"Onemogućio je administrator"</string>
     <string name="home" msgid="3256884684164448244">"Postavke početne stranice"</string>
-  <string-array name="battery_labels">
-    <item msgid="8494684293649631252">"0%"</item>
-    <item msgid="8934126114226089439">"50%"</item>
-    <item msgid="1286113608943010849">"100%"</item>
-  </string-array>
     <string name="charge_length_format" msgid="8978516217024434156">"prije <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="remaining_length_format" msgid="7886337596669190587">"Još otprilike <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="screen_zoom_summary_small" msgid="5867245310241621570">"Malo"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
index 42cc9f2..fd7eb67 100644
--- a/packages/SettingsLib/res/values-pa-rIN/arrays.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -22,7 +22,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
   <string-array name="wifi_status">
     <item msgid="1922181315419294640"></item>
-    <item msgid="8934131797783724664">"ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="8934131797783724664">"ਸਕੈਨ ਕਰ ਰਿਹਾ ਹੈ..."</item>
     <item msgid="8513729475867537913">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
     <item msgid="515055375277271756">"ਪ੍ਰਮਾਣਿਤ ਕਰ ਰਿਹਾ ਹੈ…"</item>
     <item msgid="1943354004029184381">"IP ਪਤਾ ਪ੍ਰਾਪਤ ਕਰ ਰਿਹਾ ਹੈ..."</item>
@@ -36,7 +36,7 @@
   </string-array>
   <string-array name="wifi_status_with_ssid">
     <item msgid="7714855332363650812"></item>
-    <item msgid="8878186979715711006">"ਸਕੈਨ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="8878186979715711006">"ਸਕੈਨ ਕਰ ਰਿਹਾ ਹੈ..."</item>
     <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
     <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਪ੍ਰਮਾਣਿਤ ਕਰ ਰਿਹਾ ਹੈ…"</item>
     <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਤੋਂ IP ਪਤਾ ਪ੍ਰਾਪਤ ਕਰ ਰਿਹਾ ਹੈ…"</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 320cd58..76ba0a7 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -156,7 +156,7 @@
         return intent;
     }
 
-    private static void addIntentParameters(Context context, Intent intent, String backupContext) {
+    public static void addIntentParameters(Context context, Intent intent, String backupContext) {
         if (!intent.hasExtra(EXTRA_CONTEXT)) {
             // Insert some context if none exists.
             intent.putExtra(EXTRA_CONTEXT, backupContext);
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index bf75046..8df7ac5 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -38,8 +38,10 @@
 import android.view.Window;
 import android.view.WindowManager.LayoutParams;
 import android.widget.AdapterView;
+import android.widget.FrameLayout;
 import android.widget.ListView;
 import android.widget.Toolbar;
+
 import com.android.settingslib.R;
 import com.android.settingslib.applications.InterestingConfigChanges;
 
@@ -62,6 +64,7 @@
     private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
 
     private SettingsDrawerAdapter mDrawerAdapter;
+    private FrameLayout mContentHeaderContainer;
     private DrawerLayout mDrawerLayout;
     private boolean mShowingMenu;
 
@@ -78,6 +81,7 @@
             requestWindowFeature(Window.FEATURE_NO_TITLE);
         }
         super.setContentView(R.layout.settings_with_drawer);
+        mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
         if (mDrawerLayout == null) {
             return;
@@ -174,6 +178,13 @@
         }
     }
 
+    public void setContentHeaderView(View headerView) {
+        mContentHeaderContainer.removeAllViews();
+        if (headerView != null) {
+            mContentHeaderContainer.addView(headerView);
+        }
+    }
+
     @Override
     public void setContentView(@LayoutRes int layoutResID) {
         final ViewGroup parent = (ViewGroup) findViewById(R.id.content_frame);
@@ -266,6 +277,13 @@
         }
     }
 
+    public HashMap<Pair<String, String>, Tile> getTileCache() {
+        if (sTileCache == null) {
+            getDashboardCategories();
+        }
+        return sTileCache;
+    }
+
     public void onProfileTileOpen() {
         finish();
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
index 418b138..b9c758c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
@@ -302,7 +302,7 @@
         return false;
     }
 
-    private static final Comparator<Tile> TILE_COMPARATOR =
+    public static final Comparator<Tile> TILE_COMPARATOR =
             new Comparator<Tile>() {
         @Override
         public int compare(Tile lhs, Tile rhs) {
diff --git a/packages/SettingsProvider/res/values-be-rBY/strings.xml b/packages/SettingsProvider/res/values-be-rBY/strings.xml
index 3a8557c..c164ac7 100644
--- a/packages/SettingsProvider/res/values-be-rBY/strings.xml
+++ b/packages/SettingsProvider/res/values-be-rBY/strings.xml
@@ -19,5 +19,5 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="4567566098528588863">"Сховішча налад"</string>
+    <string name="app_label" msgid="4567566098528588863">"Захоўванне налад"</string>
 </resources>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 978ca94..108814e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -216,4 +216,7 @@
 
     <!-- Default setting for ability to add users from the lock screen -->
     <bool name="def_add_users_from_lockscreen">false</bool>
+
+    <!-- Default setting for disallow oem unlock. -->
+    <bool name="def_oem_unlock_disallow">false</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 774be60..950c7d3 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2074,7 +2074,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 127;
+            private static final int SETTINGS_VERSION = 128;
 
             private final int mUserId;
 
@@ -2329,6 +2329,18 @@
                     currentVersion = 127;
                 }
 
+                if (currentVersion == 127) {
+                    // Version 127: Disable OEM unlock setting by default on some devices.
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    String defaultOemUnlockDisabled = (getContext().getResources()
+                            .getBoolean(R.bool.def_oem_unlock_disallow) ? "1" : "0");
+                    globalSettings.insertSettingLocked(
+                            Settings.Global.OEM_UNLOCK_DISALLOWED,
+                            defaultOemUnlockDisabled,
+                            SettingsState.SYSTEM_PACKAGE_NAME);
+                    currentVersion = 128;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 // Return the current version.
diff --git a/packages/Shell/res/values-b+sr+Latn/strings.xml b/packages/Shell/res/values-b+sr+Latn/strings.xml
index 185b690..fe80c22 100644
--- a/packages/Shell/res/values-b+sr+Latn/strings.xml
+++ b/packages/Shell/res/values-b+sr+Latn/strings.xml
@@ -25,11 +25,12 @@
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste delili izveštaj o grešci"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite za deljenje izveštaja o grešci bez snimka ekrana ili sačekajte da se napravi snimak ekrana"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"Izveštaji o greškama sadrže podatke iz različitih sistemskih datoteka evidencije, koji obuhvataju lične i privatne podatke (poput korišćenja aplikacija i podataka o lokaciji). Delite izveštaje o greškama samo sa aplikacijama i ljudima u koje imate poverenja."</string>
-    <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ne prikazuj ponovo"</string>
+    <!-- no translation found for bugreport_confirm (5917407234515812495) -->
+    <skip />
+    <!-- no translation found for bugreport_confirm_dont_repeat (6179945398364357318) -->
+    <skip />
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izveštaji o greškama"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Datoteka izveštaja o grešci ne može da se pročita"</string>
-    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Dodavanje detalja izveštaja o grešci u zip datoteku nije uspelo"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimci ekrana"</string>
diff --git a/packages/Shell/res/values-be-rBY/strings.xml b/packages/Shell/res/values-be-rBY/strings.xml
index fb29fbc..fc5a3b2 100644
--- a/packages/Shell/res/values-be-rBY/strings.xml
+++ b/packages/Shell/res/values-be-rBY/strings.xml
@@ -25,11 +25,12 @@
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Дакраніцеся, каб абагуліць сваю справаздачу пра памылку"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Краніце, каб абагуліць справаздачу пра памылку без здымка экрана, або чакайце атрымання здымка."</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"Справаздачы пра памылкі ўтрымліваюць даныя з розных файлаў журналаў сістэмы, якія могуць уключаць даныя, што вы лічыце канфідэнцыяльнымі (напрыклад, пра выкарыстанне праграм і даныя аб месцазнаходжанні). Абагульвайце справаздачы пра памылкі толькі з тымі людзьмі і праграмамі, якім вы давяраеце."</string>
-    <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Не паказваць зноў"</string>
+    <!-- no translation found for bugreport_confirm (5917407234515812495) -->
+    <skip />
+    <!-- no translation found for bugreport_confirm_dont_repeat (6179945398364357318) -->
+    <skip />
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Справадзачы пра памылкі"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Немагчыма прачытаць файл справаздачы пра памылкі"</string>
-    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Не атрымалася дадаць падрабязную інфармацыю справаздачы пра памылку ў файл архіва"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"без назвы"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"Падрабязнасці"</string>
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Здымак экрана"</string>
diff --git a/packages/Shell/res/values-bs-rBA/strings.xml b/packages/Shell/res/values-bs-rBA/strings.xml
index 80dddb5..c37b4ee 100644
--- a/packages/Shell/res/values-bs-rBA/strings.xml
+++ b/packages/Shell/res/values-bs-rBA/strings.xml
@@ -25,11 +25,12 @@
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Dodirnite da biste podijelili izvještaj o grešci"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Dodirnite da podijelite izveštaj o greškama bez snimka ekrana ili sačekajte da snimak bude gotov"</string>
-    <string name="bugreport_confirm" msgid="5917407234515812495">"Izvještaji o greškama sadrže podatke iz raznih zapisnika sistema koji mogu sadržavati lične i privatne informacije koje smatrate osjetljivima (poput podataka o upotrebi aplikacije ili podataka o lokaciji). Izvještaje o greškama dijelite samo sa aplikacijama i osobama kojima vjerujete."</string>
-    <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Ne prikazuj opet"</string>
+    <!-- no translation found for bugreport_confirm (5917407234515812495) -->
+    <skip />
+    <!-- no translation found for bugreport_confirm_dont_repeat (6179945398364357318) -->
+    <skip />
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Izvještaji o greškama"</string>
     <string name="bugreport_unreadable_text" msgid="586517851044535486">"Nije moguće pročitati izvještaj o grešci"</string>
-    <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Dodavanje izvještaja o greškama u zip datoteku nije uspjelo"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"neimenovano"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"Detalji"</string>
     <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Snimak ekrana"</string>
diff --git a/packages/SystemUI/res/drawable/ic_mode_edit.xml b/packages/SystemUI/res/drawable/ic_mode_edit.xml
new file mode 100644
index 0000000..8a73686
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_mode_edit.xml
@@ -0,0 +1,24 @@
+<!--
+    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="20.0dp"
+        android:height="20.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M3.0,17.25L3.0,21.0l3.75,0.0L17.81,9.94l-3.75,-3.75L3.0,17.25zM20.71,7.04c0.39,-0.3 0.39,-1.02 0.0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0.0l-1.83,1.83 3.75,3.75 1.83,-1.83z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml b/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml
new file mode 100644
index 0000000..736a04a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_branded_vpn.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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="12.0dp"
+        android:height="12.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M12.700000,10.000000c-0.800000,-2.300000 -3.000000,-4.000000 -5.700000,-4.000000c-3.300000,0.000000 -6.000000,2.700000 -6.000000,6.000000s2.700000,6.000000 6.000000,6.000000c2.600000,0.000000 4.800000,-1.700000 5.700000,-4.000000L17.000000,14.000000l0.000000,4.000000l4.000000,0.000000l0.000000,-4.000000l2.000000,0.000000l0.000000,-4.000000L12.700000,10.000000zM7.000000,14.000000c-1.100000,0.000000 -2.000000,-0.900000 -2.000000,-2.000000c0.000000,-1.100000 0.900000,-2.000000 2.000000,-2.000000s2.000000,0.900000 2.000000,2.000000C9.000000,13.100000 8.100000,14.000000 7.000000,14.000000z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_settings_20dp.xml b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
new file mode 100644
index 0000000..3170f86
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_settings_20dp.xml
@@ -0,0 +1,24 @@
+<!--
+    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="20dp"
+    android:height="20dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M19.4,13.0c0.0,-0.3 0.1,-0.6 0.1,-1.0s0.0,-0.7 -0.1,-1.0l2.1,-1.7c0.2,-0.2 0.2,-0.4 0.1,-0.6l-2.0,-3.5C19.5,5.1 19.3,5.0 19.0,5.1l-2.5,1.0c-0.5,-0.4 -1.1,-0.7 -1.7,-1.0l-0.4,-2.6C14.5,2.2 14.2,2.0 14.0,2.0l-4.0,0.0C9.8,2.0 9.5,2.2 9.5,2.4L9.1,5.1C8.5,5.3 8.0,5.7 7.4,6.1L5.0,5.1C4.7,5.0 4.5,5.1 4.3,5.3l-2.0,3.5C2.2,8.9 2.3,9.2 2.5,9.4L4.6,11.0c0.0,0.3 -0.1,0.6 -0.1,1.0s0.0,0.7 0.1,1.0l-2.1,1.7c-0.2,0.2 -0.2,0.4 -0.1,0.6l2.0,3.5C4.5,18.9 4.7,19.0 5.0,18.9l2.5,-1.0c0.5,0.4 1.1,0.7 1.7,1.0l0.4,2.6c0.0,0.2 0.2,0.4 0.5,0.4l4.0,0.0c0.2,0.0 0.5,-0.2 0.5,-0.4l0.4,-2.6c0.6,-0.3 1.2,-0.6 1.7,-1.0l2.5,1.0c0.2,0.1 0.5,0.0 0.6,-0.2l2.0,-3.5c0.1,-0.2 0.1,-0.5 -0.1,-0.6L19.4,13.0zM12.0,15.5c-1.9,0.0 -3.5,-1.6 -3.5,-3.5s1.6,-3.5 3.5,-3.5s3.5,1.6 3.5,3.5S13.9,15.5 12.0,15.5z"
+        android:fillColor="#ffffffff" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml b/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml
new file mode 100644
index 0000000..a86e5b9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_branded_vpn.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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="17.0dp"
+        android:height="17.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12.700000,10.000000c-0.800000,-2.300000 -3.000000,-4.000000 -5.700000,-4.000000c-3.300000,0.000000 -6.000000,2.700000 -6.000000,6.000000s2.700000,6.000000 6.000000,6.000000c2.600000,0.000000 4.800000,-1.700000 5.700000,-4.000000L17.000000,14.000000l0.000000,4.000000l4.000000,0.000000l0.000000,-4.000000l2.000000,0.000000l0.000000,-4.000000L12.700000,10.000000zM7.000000,14.000000c-1.100000,0.000000 -2.000000,-0.900000 -2.000000,-2.000000c0.000000,-1.100000 0.900000,-2.000000 2.000000,-2.000000s2.000000,0.900000 2.000000,2.000000C9.000000,13.100000 8.100000,14.000000 7.000000,14.000000z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index ee55ec2..8b6060f 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -37,19 +37,6 @@
             android:importantForAccessibility="yes"
             android:focusable="true" />
 
-        <TextView
-            android:id="@android:id/edit"
-            style="@style/QSBorderlessButton"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="end"
-            android:minWidth="88dp"
-            android:textAppearance="@style/TextAppearance.QS.DetailButton"
-            android:textColor="#64FFFFFF"
-            android:focusable="true"
-            android:text="@string/qs_edit"
-            android:contentDescription="@string/accessibility_quick_settings_edit"/>
-
     </FrameLayout>
 
 </com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index 751f181..26c7339 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -26,7 +26,7 @@
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
             android:background="#0000"
-            android:layout_marginTop="@dimen/status_bar_header_height"
+            android:layout_marginTop="80dp"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:paddingBottom="8dp" />
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 5d62940..678ec4e 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -37,7 +37,7 @@
         android:clipToPadding="false"
         android:orientation="horizontal"
         android:layout_alignParentEnd="true"
-        android:layout_marginTop="28dp"
+        android:layout_marginTop="4dp"
         android:layout_marginEnd="12dp">
 
         <com.android.systemui.statusbar.phone.MultiUserSwitch android:id="@+id/multi_user_switch"
@@ -52,6 +52,18 @@
                 android:scaleType="centerInside"/>
         </com.android.systemui.statusbar.phone.MultiUserSwitch>
 
+        <com.android.systemui.statusbar.AlphaOptimizedImageView
+            android:id="@android:id/edit"
+            android:layout_width="48dp"
+            android:layout_height="48dp"
+            android:clipToPadding="false"
+            android:clickable="true"
+            android:focusable="true"
+            android:src="@drawable/ic_mode_edit"
+            android:background="?android:attr/selectableItemBackgroundBorderless"
+            android:contentDescription="@string/accessibility_quick_settings_edit"
+            android:padding="14dp" />
+
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/settings_button_container"
             android:layout_width="48dp"
@@ -64,7 +76,7 @@
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:background="@drawable/ripple_drawable"
-                android:src="@drawable/ic_settings"
+                android:src="@drawable/ic_settings_20dp"
                 android:contentDescription="@string/accessibility_quick_settings_settings" />
             <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon"
                 android:layout_width="match_parent"
@@ -98,7 +110,7 @@
         android:layout_alignParentTop="true"
         android:paddingStart="16dp"
         android:paddingEnd="16dp"
-        android:paddingTop="8dp"
+        android:paddingTop="2dp"
         android:visibility="gone"
         android:textAppearance="@style/TextAppearance.StatusBar.Expanded.EmergencyCallsOnly"
         android:text="@*android:string/emergency_calls_only"
@@ -112,7 +124,7 @@
         android:layout_height="wrap_content"
         android:layout_alignParentStart="true"
         android:layout_alignParentTop="true"
-        android:layout_marginTop="8dp"
+        android:layout_marginTop="16dp"
         android:layout_marginStart="16dp"
         android:gravity="start"
         android:orientation="vertical">
@@ -169,7 +181,7 @@
         android:id="@+id/quick_qs_panel"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginTop="28dp"
+        android:layout_marginTop="52dp"
         android:layout_marginStart="12dp"
         android:layout_marginEnd="12dp"
         android:layout_alignParentEnd="true"
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f944e4b..ec2af9c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -72,7 +72,7 @@
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Čuvanje snimka ekrana..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Snimak ekrana se čuva."</string>
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snimak ekrana je napravljen."</string>
-    <string name="screenshot_saved_text" msgid="2685605830386712477">"Dodirnite da biste videli snimak ekrana."</string>
+    <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite da biste videli snimak ekrana."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Nije moguće napraviti snimak ekrana."</string>
     <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema pri čuvanju snimka ekrana."</string>
     <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Čuvanje snimka ekrana nije uspelo zbog ograničenog memorijskog prostora."</string>
@@ -119,7 +119,6 @@
     <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Signal za podatke je najjači."</string>
     <string name="accessibility_wifi_name" msgid="7202151365171148501">"Povezani ste sa <xliff:g id="WIFI">%s</xliff:g>."</string>
     <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
-    <string name="accessibility_cast_name" msgid="4026393061247081201">"Povezani smo sa uređajem <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_no_wimax" msgid="4329180129727630368">"Nema WiMAX signala."</string>
     <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX signal ima jednu crtu."</string>
     <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX signal ima dve crte."</string>
@@ -150,16 +149,12 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Nema SIM kartice."</string>
-    <string name="accessibility_cell_data" msgid="7080312242791850520">"Podaci za mobilne uređaje"</string>
-    <string name="accessibility_cell_data_on" msgid="4310018593519761767">"Podaci za mobilne uređaje su uključeni"</string>
     <string name="accessibility_cell_data_off" msgid="8000803571751407635">"Podaci za mobilne uređaje su isključeni"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth privezivanje."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Režim rada u avionu."</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"Nema SIM kartice."</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Promena mreže mobilnog operatera."</string>
-    <string name="accessibility_battery_details" msgid="7645516654955025422">"Otvori detalje o bateriji"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija je na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Baterija se puni, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procenata."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Sistemska podešavanja."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obaveštenja."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Obriši obaveštenje."</string>
@@ -197,11 +192,9 @@
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Podešavanje Ne uznemiravaj je uključeno, samo prioritetni prekidi."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Podešavanje Ne uznemiravaj je uključeno, potpuna tišina."</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Podešavanje Ne uznemiravaj je uključeno, samo alarmi."</string>
-    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Ne uznemiravaj."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Podešavanje Ne uznemiravaj je isključeno."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Podešavanje Ne uznemiravaj je isključeno."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Podešavanje Ne uznemiravaj je uključeno."</string>
-    <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth je isključen."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth je uključen."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth se povezuje."</string>
@@ -246,11 +239,6 @@
     <string name="accessibility_location_active" msgid="2427290146138169014">"Ima aktivnih zahteva za lokaciju"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Obriši sva obaveštenja."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"i još <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
-      <item quantity="one">Još <xliff:g id="NUMBER_1">%s</xliff:g> obaveštenje u grupi.</item>
-      <item quantity="few">Još <xliff:g id="NUMBER_1">%s</xliff:g> obaveštenja u grupi.</item>
-      <item quantity="other">Još <xliff:g id="NUMBER_1">%s</xliff:g> obaveštenja u grupi.</item>
-    </plurals>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Podešavanja obaveštenja"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Podešavanja za <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -260,7 +248,7 @@
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ekran je sada zaključan u vertikalnom položaju."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ekran je sada zaključan u horizontalnom položaju."</string>
     <string name="dessert_case" msgid="1295161776223959221">"Vitrina sa poslasticama"</string>
-    <string name="start_dreams" msgid="5640361424498338327">"Čuvar ekrana"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Eternet"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne uznemiravaj"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetni prekidi"</string>
@@ -272,8 +260,6 @@
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nije dostupan nijedan upareni uređaj"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Osvetljenost"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatska rotacija"</string>
-    <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatsko rotiranje ekrana"</string>
-    <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Podesi na <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotacija je zaključana"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Vertikalni prikaz"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Horizontalni prikaz"</string>
@@ -292,7 +278,6 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Veza nije uspostavljena"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi je isključen"</string>
-    <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi je uključen"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nije dostupna nijedna Wi-Fi mreža"</string>
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Prebacivanje"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Prebacivanje"</string>
@@ -328,7 +313,6 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"Aplikacija <xliff:g id="APP">%s</xliff:g> je onemogućena u bezbednom režimu."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Aplikacija ne podržava podeljeni ekran"</string>
-    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Prevucite ovde da biste koristili razdeljeni ekran"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podeli horizontalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podeli vertikalno"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođeno deljenje"</string>
@@ -346,7 +330,7 @@
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Ovo blokira SVE zvukove i vibracije uključujući alarme, muziku, video snimke i igre."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Manje hitna obaveštenja su u nastavku"</string>
-    <string name="notification_tap_again" msgid="7590196980943943842">"Dodirnite ponovo da biste otvorili"</string>
+    <string name="notification_tap_again" msgid="8524949573675922138">"Dodirnite ponovo da biste otvorili"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite nagore da biste otključali"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Prevucite od ikone za telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Prevucite od ikone za glasovnu pomoć"</string>
@@ -424,7 +408,7 @@
     <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>
-    <string name="screen_pinning_description" msgid="7238941806855968768">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad da biste ga otkačili."</string>
+    <string name="screen_pinning_description" msgid="3577937698406151604">"Zbog toga se on stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad 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>
@@ -434,13 +418,11 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dozvoli"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dijalog za jačinu zvuka"</string>
-    <string name="volumeui_notification_text" msgid="8819536904234337445">"Dodirnite da biste vratili original."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da biste vratili original."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite profil za Work"</string>
     <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Dodirnite da biste uključili zvuk."</string>
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite da biste podesili na vibraciju. Zvuk usluga pristupačnosti će možda biti isključen."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dodirnite da biste isključili zvuk. Zvuk usluga pristupačnosti će možda biti isključen."</string>
-    <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrole za jačinu zvuka (%s) su prikazane. Prevucite nagore da biste ih odbacili."</string>
-    <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole za jačinu zvuka su sakrivene"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Tjuner za korisnički interfejs sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikazuj ugrađeni procenat baterije"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazivanje nivoa napunjenosti baterije u procentima unutar ikone na statusnoj traci kada se baterija ne puni"</string>
@@ -485,24 +467,19 @@
     <string name="block" msgid="2734508760962682611">"Blokiraj sva obaveštenja"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Ne isključuj zvuk"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Ne isključuju zvuk niti blokiraj"</string>
-    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Napredne kontrole za obaveštenja"</string>
-    <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>
-    <string name="user_unspecified_importance" msgid="361613856933432117">"Važnost: Automatski"</string>
-    <string name="blocked_importance" msgid="5035073235408414397">"Važnost: 0. nivo"</string>
-    <string name="min_importance" msgid="560779348928574878">"Važnost: 1. nivo"</string>
-    <string name="low_importance" msgid="7571498511534140">"Važnost: 2. nivo"</string>
-    <string name="default_importance" msgid="7609889614553354702">"Važnost: 3. nivo"</string>
-    <string name="high_importance" msgid="3441537905162782568">"Važnost: 4. nivo"</string>
-    <string name="max_importance" msgid="4880179829869865275">"Važnost: 5. nivo"</string>
-    <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Aplikacija određuje važnost svakog obaveštenja."</string>
-    <string name="notification_importance_blocked" msgid="4237497046867398057">"Nikada ne prikazuj obaveštenja iz ove aplikacije"</string>
-    <string name="notification_importance_min" msgid="7844224511187027155">"Bez prekida režima celog ekrana, zavirivanja, zvuka ili vibracije. Sakrij na zaključanom ekranu i statusnoj traci."</string>
-    <string name="notification_importance_low" msgid="7950291702044409847">"Bez prekida režima celog ekrana, zavirivanja, zvuka ili vibracije."</string>
-    <string name="notification_importance_default" msgid="5924405820269074915">"Bez prekida režima celog ekrana ili zavirivanja."</string>
-    <string name="notification_importance_high" msgid="1729480727023990427">"Uvek zaviruj. Bez prekida režima celog ekrana."</string>
-    <string name="notification_importance_max" msgid="2508384624461849111">"Uvek zaviruj i dozvoli prekid režima celog ekrana."</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletna podešavanja važnosti"</string>
+    <string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Veoma mala važnost"</string>
+    <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
+    <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
+    <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
+    <string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ova obaveštenja se prikazuju bez zvuka"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite da ova obaveštenja emituju zvuk"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Nakratko se prikazuju na ekranu i emituju zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikazuju se u vrhu liste obaveštenja, nakratko se prikazuju na ekranu i emituju zvuk"</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>
@@ -617,16 +594,10 @@
   </string-array>
     <string name="other" msgid="4060683095962566764">"Drugo"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Razdelnik podeljenog ekrana"</string>
-    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Režim celog ekrana za levi ekran"</string>
-    <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"Levi ekran 70%"</string>
-    <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"Levi ekran 50%"</string>
-    <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"Levi ekran 30%"</string>
-    <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"Režim celog ekrana za donji ekran"</string>
-    <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"Režim celog ekrana za gornji ekran"</string>
-    <string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"Gornji ekran 70%"</string>
-    <string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"Gornji ekran 50%"</string>
-    <string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"Gornji ekran 30%"</string>
-    <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"Režim celog ekrana za donji ekran"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomeri nadole"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomeri ulevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomeri udesno"</string>
     <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite da biste izmenili."</string>
     <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Dvaput dodirnite da biste dodali."</string>
     <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija. Dvaput dodirnite da biste izabrali."</string>
@@ -636,17 +607,9 @@
     <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjena"</string>
     <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"Pločica <xliff:g id="TILE_NAME">%1$s</xliff:g> je premeštena na <xliff:g id="POSITION">%2$d</xliff:g>. poziciju"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivač za Brza podešavanja."</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"Obaveštenja za <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće funkcionisati sa podeljenim ekranom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava podeljeni ekran."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Otvori Podešavanja."</string>
-    <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Otvori Brza podešavanja."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Zatvori Brza podešavanja."</string>
-    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Alarm je podešen."</string>
-    <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Nema interneta."</string>
-    <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvori detalje."</string>
-    <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori podešavanja za <xliff:g id="ID_1">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Izmeni redosled podešavanja."</string>
-    <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"<xliff:g id="ID_1">%1$d</xliff:g>. strana od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="accessibility_quick_settings_expand" msgid="4982484435775933070">"Proširi Brza podešavanja."</string>
+    <!-- no translation found for accessibility_quick_settings_page (5032979051755200721) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
index 403c10d..d026d2c 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings_tv.xml
@@ -24,8 +24,7 @@
     <string name="pip_play" msgid="674145557658227044">"Pusti"</string>
     <string name="pip_pause" msgid="8412075640017218862">"Pauziraj"</string>
     <string name="pip_hold_home" msgid="340086535668778109"><b>"POČETNI EKRAN"</b>" kont. PIP"</string>
-    <string name="pip_onboarding_title" msgid="7850436557670253991">"Slika u slici"</string>
-    <string name="pip_onboarding_description" msgid="4028124563309465267">"Na ovaj način će video biti prikazan dok ne pustite neki drugi. Pritisnite i zadržite "<b>"POČETNA"</b>" da biste ga kontrolisali."</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Pritisnite i zadržite dugme POČETNI EKRAN da biste kontrolisali PIP"</string>
     <string name="pip_onboarding_button" msgid="3957426748484904611">"Važi"</string>
     <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings.xml b/packages/SystemUI/res/values-be-rBY/strings.xml
index 12ba0cd..71e3cb18 100644
--- a/packages/SystemUI/res/values-be-rBY/strings.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings.xml
@@ -53,8 +53,8 @@
     <string name="bluetooth_tethered" msgid="7094101612161133267">"Прывязаныя праз Bluetooth"</string>
     <string name="status_bar_input_method_settings_configure_input_methods" msgid="3504292471512317827">"Налада метадаў уводу"</string>
     <string name="status_bar_use_physical_keyboard" msgid="7551903084416057810">"Фізічная клавіятура"</string>
-    <string name="usb_device_permission_prompt" msgid="834698001271562057">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> атрымлiваць доступ да прылады USB?"</string>
-    <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Дазволіць праграме <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да USB-аксесуара?"</string>
+    <string name="usb_device_permission_prompt" msgid="834698001271562057">"Дазволіць праыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> атрымлiваць доступ да прылады USB?"</string>
+    <string name="usb_accessory_permission_prompt" msgid="5171775411178865750">"Дазволіць прыкладанню <xliff:g id="APPLICATION">%1$s</xliff:g> доступ да прылады USB?"</string>
     <string name="usb_device_confirm_prompt" msgid="5161205258635253206">"Адкрыць <xliff:g id="ACTIVITY">%1$s</xliff:g>, калі гэтая USB-прылада падлучаная?"</string>
     <string name="usb_accessory_confirm_prompt" msgid="3808984931830229888">"Адкрыць <xliff:g id="ACTIVITY">%1$s</xliff:g>, калі гэтая USB-прылада падлучаная?"</string>
     <string name="usb_accessory_uri_prompt" msgid="513450621413733343">"Няма ўсталяв. прыкл. для працы з гэтай прыл. USB. Больш падраб. пра гэтую прыл.: <xliff:g id="URL">%1$s</xliff:g>"</string>
@@ -73,7 +73,7 @@
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Захаванне скрыншота..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Скрыншот захаваны."</string>
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Скрыншот зроблены"</string>
-    <string name="screenshot_saved_text" msgid="2685605830386712477">"Дакраніцеся, каб прагледзець здымак экрана."</string>
+    <string name="screenshot_saved_text" msgid="1152839647677558815">"Націсніце, каб прагледзець скрыншот"</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Не атрымалася зрабiць скрыншот."</string>
     <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Падчас захавання скрыншота адбылася памылка."</string>
     <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Немагчыма захаваць здымак экрана, бо мала месца ў памяці."</string>
@@ -98,7 +98,7 @@
     <string name="voice_assist_label" msgid="3956854378310019854">"адкрыць галасавую дапамогу"</string>
     <string name="camera_label" msgid="7261107956054836961">"адкрыць камеру"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Выберыце новы макет заданняў"</string>
-    <string name="cancel" msgid="6442560571259935130">"Скасаваць"</string>
+    <string name="cancel" msgid="6442560571259935130">"Адмяніць"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка сумяшчальнасці маштаба."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Маштабаванне малых элементаў для большага экрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-сувязь."</string>
@@ -120,7 +120,6 @@
     <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Поўны сігнал перадачы дадзеных."</string>
     <string name="accessibility_wifi_name" msgid="7202151365171148501">"Падключаны да <xliff:g id="WIFI">%s</xliff:g>."</string>
     <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
-    <string name="accessibility_cast_name" msgid="4026393061247081201">"Ёсць падключэнне да <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_no_wimax" msgid="4329180129727630368">"Няма сiгналу WiMAX."</string>
     <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"Адзiн слупок сiгналу WiMAX."</string>
     <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"Два слупкi сiгналу WiMAX."</string>
@@ -136,7 +135,7 @@
     <string name="accessibility_three_bars" msgid="2648241415119396648">"Тры слупкi."</string>
     <string name="accessibility_signal_full" msgid="9122922886519676839">"Сігнал поўны."</string>
     <string name="accessibility_desc_on" msgid="2385254693624345265">"Уключана."</string>
-    <string name="accessibility_desc_off" msgid="6475508157786853157">"Выключана."</string>
+    <string name="accessibility_desc_off" msgid="6475508157786853157">"Адключана."</string>
     <string name="accessibility_desc_connected" msgid="8366256693719499665">"Падключана."</string>
     <string name="accessibility_desc_connecting" msgid="3812924520316280149">"Падлучэнне."</string>
     <string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
@@ -151,18 +150,14 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Няма SIM-карты."</string>
-    <string name="accessibility_cell_data" msgid="7080312242791850520">"Сотавая перадача даных"</string>
-    <string name="accessibility_cell_data_on" msgid="4310018593519761767">"Сотавая перадача даных уключана"</string>
     <string name="accessibility_cell_data_off" msgid="8000803571751407635">"Мабільная перадача даных адключана"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Сувязь па Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Рэжым палёту."</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"Няма SIM-карты."</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Змяненне аператара сеткі."</string>
-    <string name="accessibility_battery_details" msgid="7645516654955025422">"Паказаць падрабязную інфармацыю пра акумулятар"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for accessibility_battery_level (7451474187113371965) -->
     <skip />
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Зарадка акумулятара, працэнтаў: <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g>."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Сістэмныя налады."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Апавяшчэнні."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Выдаліць апавяшчэнне."</string>
@@ -200,11 +195,9 @@
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Рэжым «Не турбаваць» укл., толькі прыярытэтныя."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Рэжым «Не турбаваць» укл., поўная цішыня."</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Рэжым «Не турбаваць» укл., толькі будзільнікі."</string>
-    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Не турбаваць."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Рэжым «Не турбаваць» выкл."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Рэжым «Не турбаваць» выкл."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Рэжым «Не турбаваць» укл."</string>
-    <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth выключаны."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth уключаны."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth падлучаецца."</string>
@@ -249,12 +242,6 @@
     <string name="accessibility_location_active" msgid="2427290146138169014">"Ёсць актыўныя запыты пра месцазнаходжанне"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Выдалiць усе апавяшчэннi."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
-      <item quantity="one">Яшчэ <xliff:g id="NUMBER_1">%s</xliff:g> апавяшчэнне ўнутры.</item>
-      <item quantity="few">Яшчэ <xliff:g id="NUMBER_1">%s</xliff:g> апавяшчэнні ўнутры.</item>
-      <item quantity="many">Яшчэ <xliff:g id="NUMBER_1">%s</xliff:g> апавяшчэнняў унутры.</item>
-      <item quantity="other">Яшчэ <xliff:g id="NUMBER_1">%s</xliff:g> апавяшчэння ўнутры.</item>
-    </plurals>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Налады апавяшчэнняў"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Налады <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Экран паварочваецца аўтаматычна."</string>
@@ -264,7 +251,7 @@
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Цяпер экран заблакіраваны ў альбомнай арыентацыі."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Цяпер экран заблакiраваны ў кніжнай арыентацыі."</string>
     <string name="dessert_case" msgid="1295161776223959221">"Вітрына з дэсертамі"</string>
-    <string name="start_dreams" msgid="5640361424498338327">"Экранная застаўка"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Мроi"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Не турбаваць"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Толькі прыярытэтныя"</string>
@@ -276,8 +263,6 @@
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Няма даступных спалучаных прылад"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Яркасць"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Аўтапаварот"</string>
-    <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Аўтаматычны паварот экрана"</string>
-    <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Усталявана на <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Паварот заблакіраваны"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Кніжная арыентацыя"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Альбомная арыентацыя"</string>
@@ -296,7 +281,6 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Няма падключэння"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Няма сеткi"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi адключаны"</string>
-    <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi уключаны"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Няма даступнай сеткі Wi-Fi"</string>
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляцыя"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Ідзе перадача"</string>
@@ -323,7 +307,7 @@
     <string name="quick_settings_cellular_detail_data_limit" msgid="56011158504994128">"Ліміт <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_cellular_detail_data_warning" msgid="2440098045692399009">"Папярэджанне: <xliff:g id="DATA_LIMIT">%s</xliff:g>"</string>
     <string name="quick_settings_work_mode_label" msgid="6244915274350490429">"Рэжым працы"</string>
-    <string name="recents_empty_message" msgid="808480104164008572">"Няма нядаўніх элементаў"</string>
+    <string name="recents_empty_message" msgid="808480104164008572">"Няма апошніх элементаў"</string>
     <string name="recents_empty_message_dismissed_all" msgid="2791312568666558651">"Вы ачысцілі усё"</string>
     <string name="recents_app_info_button_label" msgid="2890317189376000030">"Звесткі аб праграме"</string>
     <string name="recents_lock_to_app_button_label" msgid="6942899049072506044">"замацаванне экрана"</string>
@@ -332,7 +316,6 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> адключана ў бяспечным рэжыме."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Ачысціць усё"</string>
     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Праграма не падтрымлівае функцыю дзялення экрана"</string>
-    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Перацягніце сюды, каб перайсці ў рэжым падзеленага экрана"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Падзяліць гарызантальна"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Падзяліць вертыкальна"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Падзяліць іншым чынам"</string>
@@ -350,8 +333,7 @@
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Гэта заблакіруе ЎСЕ гукі і вібрацыі, у тым ліку ад будзільнікаў, музыкі, відэа і гульняў."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Менш тэрміновыя апавяшчэнні ніжэй"</string>
-    <!-- no translation found for notification_tap_again (7590196980943943842) -->
-    <skip />
+    <string name="notification_tap_again" msgid="8524949573675922138">"Краніце яшчэ раз, каб адкрыць"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Правядзіце пальцам уверх, каб разблакіраваць"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Тэлефон: правядзіце пальцам ад значка"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Галасавая дапамога: правядзіце пальцам ад значка"</string>
@@ -389,7 +371,7 @@
     <string name="user_logout_notification_text" msgid="3350262809611876284">"Выканаць выхад бягучага карыстальніка"</string>
     <string name="user_logout_notification_action" msgid="1195428991423425062">"ВЫКАНАЦЬ ВЫХАД КАРЫСТАЛЬНІКА"</string>
     <string name="user_add_user_title" msgid="4553596395824132638">"Дадаць новага карыстальніка?"</string>
-    <string name="user_add_user_message_short" msgid="2161624834066214559">"Пасля стварэння профіля яго трэба наладзіць.\n\nЛюбы карыстальнік прылады можа абнаўляць праграмы ўсіх іншых карыстальнікаў."</string>
+    <string name="user_add_user_message_short" msgid="2161624834066214559">"Калі вы дадаяце новага карыстальніка, ён павінен наладзіць свой раздзел.\n\nЛюбы карыстальнік можа абнаўляць праграмы для ўсіх астатніх карыстальнікаў."</string>
     <string name="user_remove_user_title" msgid="4681256956076895559">"Выдаліць карыстальніка?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Усе праграмы і даныя гэтага карыстальніка будуць выдалены."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Выдаліць"</string>
@@ -429,7 +411,7 @@
     <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="7238941806855968768">"Будзе паказвацца, пакуль не адмацуеце. Дакраніцеся і ўтрымлівайце кнопку \"Назад\", каб адмацаваць."</string>
+    <string name="screen_pinning_description" msgid="3577937698406151604">"Будзе паказвацца, пакуль не адмацуеце. Дакраніцеся і ўтрымлівайце кнопку «Назад», каб адмацаваць."</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>
@@ -437,15 +419,13 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Схаваць"</string>
     <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> хоча быць дыялогам гучнасці."</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Дазволіць"</string>
-    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Адмовіць"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Адхiлiць"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> з\'яўляецца дыялогам гучнасці"</string>
-    <string name="volumeui_notification_text" msgid="8819536904234337445">"Дакраніцеся, каб аднавіць арыгінал."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Націсніце, каб аднавіць арыгінал."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Вы выкарыстоўваеце свой працоўны профіль"</string>
-    <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Дакраніцеся, каб уключыць гук."</string>
-    <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Дакраніцеся, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
-    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Дакраніцеся, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
-    <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Паказваецца наступная колькасць рэгулятараў гучнасці: %s. Правядзіце пальцам уверх, каб закрыць іх."</string>
-    <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Рэгулятары гучнасці схаваны"</string>
+    <string name="volume_stream_content_description_unmute" msgid="4436631538779230857">"%1$s. Краніце, каб уключыць гук."</string>
+    <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Краніце, каб уключыць вібрацыю. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
+    <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Краніце, каб адключыць гук. Можа быць адключаны гук службаў спецыяльных магчымасцей."</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Наладка сістэмнага інтэрфейсу карыстальніка"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Паказваць працэнт зараду акумулятара"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Паказваць працэнт узроўню акумулятара ўнутры значка панэлі стану, калі ён не зараджаецца"</string>
@@ -490,24 +470,19 @@
     <string name="block" msgid="2734508760962682611">"Блакіраваць усе апавяшчэнні"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Не адключаць гук"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Не адключаць гук і не блакіраваць"</string>
-    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Пашыранае кіраванне апавяшчэннямі"</string>
-    <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>
-    <string name="user_unspecified_importance" msgid="361613856933432117">"Важнасць: аўтаматычна"</string>
-    <string name="blocked_importance" msgid="5035073235408414397">"Важнасць: узровень 0"</string>
-    <string name="min_importance" msgid="560779348928574878">"Важнасць: узровень 1"</string>
-    <string name="low_importance" msgid="7571498511534140">"Важнасць: узровень 2"</string>
-    <string name="default_importance" msgid="7609889614553354702">"Важнасць: узровень 3"</string>
-    <string name="high_importance" msgid="3441537905162782568">"Важнасць: узровень 4"</string>
-    <string name="max_importance" msgid="4880179829869865275">"Важнасць: узровень 5"</string>
-    <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Праграма вызначае важнасць кожнага апавяшчэння."</string>
-    <string name="notification_importance_blocked" msgid="4237497046867398057">"Ніколі не паказваць апавяшчэнні ад гэтай праграмы."</string>
-    <string name="notification_importance_min" msgid="7844224511187027155">"Не перап. рэжым поўн. экр., не дазв. карот. паказ, гук або вібр. Хаваць з экр. блак. і панэлі стану."</string>
-    <string name="notification_importance_low" msgid="7950291702044409847">"Не перапыняць рэжым поўнага экрана, не дазваляць кароткі паказ, прайгранне гуку або вібрацыю."</string>
-    <string name="notification_importance_default" msgid="5924405820269074915">"Не перапыняць рэжым поўнага экрана і не дазваляць кароткі паказ."</string>
-    <string name="notification_importance_high" msgid="1729480727023990427">"Заўсёды дазваляць кароткі паказ. Не перапыняць рэжым поўнага экрана."</string>
-    <string name="notification_importance_max" msgid="2508384624461849111">"Заўсёды дазваляць кароткі паказ, дазваляць перапыняць рэжым поўнага экрана."</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Паказаць поўны спіс налад важнасці"</string>
+    <string name="blocked_importance" msgid="5198578988978234161">"Заблакiравана"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Мінімальная важнасць"</string>
+    <string name="low_importance" msgid="4109929986107147930">"Нізкая важнасць"</string>
+    <string name="default_importance" msgid="8192107689995742653">"Звычайная важнасць"</string>
+    <string name="high_importance" msgid="1527066195614050263">"Высокая важнасць"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Пільная важнасць"</string>
+    <string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколі не паказваць гэтыя апавяшчэнні"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Бязгучна паказваць унізе спіса апавяшчэнняў"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Паказваць гэтыя апавяшчэнні бязгучна"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Дазволіць гэтым апавяшчэнням прайграваць гукі"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Хутка паказаць на экране і дазволіць прайграванне гуку"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Паказваць уверсе спіса апавяшчэнняў, хутка паказаць на экране і дазволіць прайграванне гуку"</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>
@@ -515,7 +490,7 @@
     <string name="night_mode" msgid="3540405868248625488">"Начны рэжым"</string>
     <string name="calibrate_display" msgid="5974642573432039217">"Каліброўка дысплэя"</string>
     <string name="night_mode_on" msgid="5597545513026541108">"Уключана"</string>
-    <string name="night_mode_off" msgid="8035605276956057508">"Выключана"</string>
+    <string name="night_mode_off" msgid="8035605276956057508">"Адключана"</string>
     <string name="turn_on_automatically" msgid="4167565356762016083">"Уключаць аўтаматычна"</string>
     <string name="turn_on_auto_summary" msgid="2190994512406701520">"Пераключэнне ў начны рэжым у залежнасці ад канкрэтнай мясцовасці і часу сутак"</string>
     <string name="when_night_mode_on" msgid="2969436026899172821">"Калі ўключаны Начны рэжым"</string>
@@ -585,7 +560,7 @@
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Эканомія трафіку ўключана"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Эканомія трафіку адключана"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Уключана"</string>
-    <string name="switch_bar_off" msgid="8803270596930432874">"Выключана"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Адключана"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Панэль навігацыі"</string>
     <string name="start" msgid="6873794757232879664">"Пачатак"</string>
     <string name="center" msgid="4327473927066010960">"Цэнтр"</string>
@@ -605,7 +580,7 @@
     <string name="keycode" msgid="7335281375728356499">"Код клавішы"</string>
     <string name="keycode_description" msgid="1403795192716828949">"Кнопка Код клавішы дазваляе дадаваць клавішы ў Панэль навігацыі. Пры націску гэтай кнопкі эмулюецца выбраная клавіша. Спачатку трэба выбраць клавішу для кнопкі, а потым відарыс, які будзе паказвацца на кнопцы."</string>
     <string name="select_keycode" msgid="7413765103381924584">"Выберыце клавішу клавіятуры"</string>
-    <string name="preview" msgid="9077832302472282938">"Перадпрагляд"</string>
+    <string name="preview" msgid="9077832302472282938">"Папярэдні прагляд"</string>
     <string name="drag_to_add_tiles" msgid="7058945779098711293">"Перацягніце, каб дадаць пліткі"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Перацягніце сюды, каб выдаліць"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Рэдагаваць"</string>
@@ -622,16 +597,10 @@
   </string-array>
     <string name="other" msgid="4060683095962566764">"Іншае"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Раздзяляльнік падзеленага экрана"</string>
-    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Левы экран – поўнаэкранны рэжым"</string>
-    <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"Левы экран – 70%"</string>
-    <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"Левы экран – 50%"</string>
-    <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"Левы экран – 30%"</string>
-    <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"Правы экран – поўнаэкранны рэжым"</string>
-    <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"Верхні экран – поўнаэкранны рэжым"</string>
-    <string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"Верхні экран – 70%"</string>
-    <string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"Верхні экран – 50%"</string>
-    <string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"Верхні экран – 30%"</string>
-    <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"Ніжні экран – поўнаэкранны рэжым"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перамясціць уніз"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перамясціць уверх"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Перамясціць улева"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Перамясціць управа"</string>
     <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Краніце двойчы, каб рэдагаваць."</string>
     <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g>. Краніце двойчы, каб дадаць."</string>
     <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Месца: <xliff:g id="POSITION">%1$d</xliff:g>. Краніце двойчы, каб выбраць."</string>
@@ -641,17 +610,9 @@
     <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"Плітка <xliff:g id="TILE_NAME">%1$s</xliff:g> выдалена"</string>
     <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> перамешчана ў наступнае месца: <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Рэдактар хуткіх налад."</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"Апавяшчэнне <xliff:g id="ID_1">%1$s</xliff:g>: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Праграма можа не працаваць у рэжыме дзялення экрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Адкрыць налады."</string>
-    <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Адкрыць хуткія налады."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Закрыць хуткія налады."</string>
-    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Будзільнік пастаўлены."</string>
-    <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Вы ўвайшлі як <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Няма інтэрнэту."</string>
-    <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Паказаць падрабязную інфармацыю."</string>
-    <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Адкрыць налады <xliff:g id="ID_1">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Змяніць парадак налад."</string>
-    <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Старонка <xliff:g id="ID_1">%1$d</xliff:g> з <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="accessibility_quick_settings_expand" msgid="4982484435775933070">"Разгарнуць хуткія налады."</string>
+    <!-- no translation found for accessibility_quick_settings_page (5032979051755200721) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-be-rBY/strings_tv.xml b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
index 6eb71e0..dab7938 100644
--- a/packages/SystemUI/res/values-be-rBY/strings_tv.xml
+++ b/packages/SystemUI/res/values-be-rBY/strings_tv.xml
@@ -24,8 +24,7 @@
     <string name="pip_play" msgid="674145557658227044">"Прайграць"</string>
     <string name="pip_pause" msgid="8412075640017218862">"Прыпыніць"</string>
     <string name="pip_hold_home" msgid="340086535668778109">"Утрым. "<b>"HOME"</b>" для кір. PIP"</string>
-    <string name="pip_onboarding_title" msgid="7850436557670253991">"Відарыс у відарысе"</string>
-    <string name="pip_onboarding_description" msgid="4028124563309465267">"Гэта дазваляе захоўваць ваша відэа ў полі зроку, пакуль вы не пачняце прайграванне іншага. Націсніце і ўтрымлівайце "<b>"HOME"</b>" для кіравання."</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Націсніце і ўтрымлівайце кнопку HOME для кіравання PIP"</string>
     <string name="pip_onboarding_button" msgid="3957426748484904611">"Зразумела"</string>
     <string name="recents_tv_dismiss" msgid="3555093879593377731">"Адхіліць"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings.xml b/packages/SystemUI/res/values-bs-rBA/strings.xml
index c0b8985..d0590e9 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings.xml
@@ -72,7 +72,7 @@
     <string name="screenshot_saving_title" msgid="8242282144535555697">"Spašavanje snimka ekrana..."</string>
     <string name="screenshot_saving_text" msgid="2419718443411738818">"Spašavanje snimka ekrana u toku."</string>
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Ekran snimljen."</string>
-    <string name="screenshot_saved_text" msgid="2685605830386712477">"Dodirnite za prikaz snimka ekrana."</string>
+    <string name="screenshot_saved_text" msgid="1152839647677558815">"Dodirnite za prikaz snimka ekrana."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Došlo je do greške prilikom snimanja ekrana."</string>
     <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Došlo je do problema prilikom spašavanja snimka ekrana."</string>
     <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snimak ekrana se ne može sačuvati zbog manjka prostora za pohranu."</string>
@@ -97,7 +97,7 @@
     <string name="voice_assist_label" msgid="3956854378310019854">"otvori glasovnu pomoć"</string>
     <string name="camera_label" msgid="7261107956054836961">"otvori kameru"</string>
     <string name="recents_caption_resize" msgid="3517056471774958200">"Izaberite novi raspored zadataka"</string>
-    <string name="cancel" msgid="6442560571259935130">"Otkaži"</string>
+    <string name="cancel" msgid="6442560571259935130">"Prekini"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Dugme za uvećavanje u slučaju nekompatibilnosti."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Uvećani prikaz manjeg ekrana na većem ekranu."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth je povezan."</string>
@@ -119,7 +119,6 @@
     <string name="accessibility_data_signal_full" msgid="2708384608124519369">"Signal za prijenos podataka pun."</string>
     <string name="accessibility_wifi_name" msgid="7202151365171148501">"Povezan na <xliff:g id="WIFI">%s</xliff:g>."</string>
     <string name="accessibility_bluetooth_name" msgid="8441517146585531676">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
-    <string name="accessibility_cast_name" msgid="4026393061247081201">"Povezan na <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_no_wimax" msgid="4329180129727630368">"Nema WiMAX signala."</string>
     <string name="accessibility_wimax_one_bar" msgid="4170994299011863648">"WiMAX signal na jednoj crtici."</string>
     <string name="accessibility_wimax_two_bars" msgid="9176236858336502288">"WiMAX signal na dvije crtice."</string>
@@ -150,16 +149,12 @@
     <string name="accessibility_data_connection_edge" msgid="4477457051631979278">"Edge"</string>
     <string name="accessibility_data_connection_wifi" msgid="2324496756590645221">"Wi-Fi"</string>
     <string name="accessibility_no_sim" msgid="8274017118472455155">"Nema SIM kartice."</string>
-    <string name="accessibility_cell_data" msgid="7080312242791850520">"Mobilni podaci"</string>
-    <string name="accessibility_cell_data_on" msgid="4310018593519761767">"Prijenos mobilnih podataka uključen"</string>
     <string name="accessibility_cell_data_off" msgid="8000803571751407635">"Mobilni podaci isključeni"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Dijeljenje Bluetooth veze."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Način rada u avionu."</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"Nema SIM kartice."</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Promjena mreže operatera."</string>
-    <string name="accessibility_battery_details" msgid="7645516654955025422">"Otvori detalje o potrošnji baterije"</string>
     <string name="accessibility_battery_level" msgid="7451474187113371965">"Baterija na <xliff:g id="NUMBER">%d</xliff:g> posto."</string>
-    <string name="accessibility_battery_level_charging" msgid="1147587904439319646">"Punjenje baterije, <xliff:g id="BATTERY_PERCENTAGE">%d</xliff:g> procenata."</string>
     <string name="accessibility_settings_button" msgid="799583911231893380">"Postavke sistema."</string>
     <string name="accessibility_notifications_button" msgid="4498000369779421892">"Obavještenja."</string>
     <string name="accessibility_remove_notification" msgid="3603099514902182350">"Ukloniti obavještenje."</string>
@@ -197,11 +192,9 @@
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Opcija Ne ometaj je uključena, čut će se samo prioritetna obavještenja."</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Opcija Ne ometaj je uključena, potpuna tišina."</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Opcija Ne ometaj je uključena, čut će se samo alarmi."</string>
-    <string name="accessibility_quick_settings_dnd" msgid="6607873236717185815">"Ne ometaj."</string>
     <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"Opcija Ne ometaj je isključena."</string>
     <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"Opcija Ne ometaj je isključena."</string>
     <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"Opcija Ne ometaj je uključena."</string>
-    <string name="accessibility_quick_settings_bluetooth" msgid="6341675755803320038">"Bluetooth."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth isključen."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth uključen."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Bluetooth se povezuje."</string>
@@ -246,11 +239,6 @@
     <string name="accessibility_location_active" msgid="2427290146138169014">"Aktiviran je zahtjev za lokaciju"</string>
     <string name="accessibility_clear_all" msgid="5235938559247164925">"Uklanjanje svih obavještenja."</string>
     <string name="notification_group_overflow_indicator" msgid="1863231301642314183">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
-    <plurals name="notification_group_overflow_description" formatted="false" msgid="4579313201268495404">
-      <item quantity="one">Još <xliff:g id="NUMBER_1">%s</xliff:g> obavještenje unutra.</item>
-      <item quantity="few">Još <xliff:g id="NUMBER_1">%s</xliff:g> obavještenja unutra.</item>
-      <item quantity="other">Još <xliff:g id="NUMBER_1">%s</xliff:g> obavještenja unutra.</item>
-    </plurals>
     <string name="status_bar_notification_inspect_item_title" msgid="5668348142410115323">"Postavke obavještenja"</string>
     <string name="status_bar_notification_app_settings_title" msgid="5525260160341558869">"Postavke aplikacije <xliff:g id="APP_NAME">%s</xliff:g>"</string>
     <string name="accessibility_rotation_lock_off" msgid="4062780228931590069">"Ekran će se automatski rotirati."</string>
@@ -260,7 +248,7 @@
     <string name="accessibility_rotation_lock_on_landscape_changed" msgid="3135965553707519743">"Ekran je sada zaključan u vodoravnom položaju."</string>
     <string name="accessibility_rotation_lock_on_portrait_changed" msgid="8922481981834012126">"Ekran je sada zaključan u uspravnom položaju."</string>
     <string name="dessert_case" msgid="1295161776223959221">"Slika sa desertima"</string>
-    <string name="start_dreams" msgid="5640361424498338327">"Čuvar ekrana"</string>
+    <string name="start_dreams" msgid="7219575858348719790">"Sanjarenje"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
     <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Ne ometaj"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Samo prioritetni prekidi"</string>
@@ -272,8 +260,6 @@
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Nema dostupnih uparenih uređaja"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Osvjetljenje"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Automatsko rotiranje"</string>
-    <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Automatsko rotiranje ekrana"</string>
-    <string name="accessibility_quick_settings_rotation_value" msgid="1428962304214992318">"Postaviti način rada: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Rotiranje je zaključano"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Uspravno"</string>
     <string name="quick_settings_rotation_locked_landscape_label" msgid="8553157770061178719">"Vodoravno"</string>
@@ -292,7 +278,6 @@
     <string name="quick_settings_wifi_not_connected" msgid="7171904845345573431">"Nije povezano"</string>
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Nema mreže"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi isključen"</string>
-    <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi uključen"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Nema dostupnih Wi-Fi mreža"</string>
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Prebacivanje"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Prebacivanje"</string>
@@ -328,7 +313,6 @@
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> je onemogućena u sigurnom načinu rada."</string>
     <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Obriši sve"</string>
     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Aplikacija ne podržava dijeljenje ekrana."</string>
-    <string name="recents_drag_hint_message" msgid="2649739267073203985">"Povucite ovdje za korištenje podijeljenog ekrana"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Podjela po horizontali"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Podjela po vertikali"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Prilagođena podjela"</string>
@@ -346,8 +330,7 @@
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Ovim se blokiraju SVI zvukovi i vibracije, uključujući alarme, muziku, video zapise i igre."</string>
     <string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Prikaži manje važna obavještenja ispod"</string>
-    <!-- no translation found for notification_tap_again (7590196980943943842) -->
-    <skip />
+    <string name="notification_tap_again" msgid="8524949573675922138">"Dodirnite ponovo da otvorite"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Prevucite prema gore da otključate"</string>
     <string name="phone_hint" msgid="4872890986869209950">"Prevucite preko ikone da otvorite telefon"</string>
     <string name="voice_hint" msgid="8939888732119726665">"Prevucite preko ikone za glasovnu pomoć"</string>
@@ -425,7 +408,7 @@
     <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>
-    <string name="screen_pinning_description" msgid="7238941806855968768">"Ovim ekran ostaje prikazan dok ga ne otkačite. Da biste ga otkačili dodirnite i držite Nazad."</string>
+    <string name="screen_pinning_description" msgid="3577937698406151604">"Ovim ekran ostaje prikazan dok ga ne otkačite. Da biste ga otkačili dodirnite i držite Nazad."</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>
@@ -435,15 +418,13 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Dozvoli"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Odbij"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> je dijaloški okvir za jačinu zvuka"</string>
-    <string name="volumeui_notification_text" msgid="8819536904234337445">"Dodirnite za povrat originala."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Dodirnite da vratite original."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Koristite svoj profil za posao"</string>
     <!-- String.format failed for translation -->
     <!-- no translation found for volume_stream_content_description_unmute (4436631538779230857) -->
     <skip />
     <string name="volume_stream_content_description_vibrate" msgid="1187944970457807498">"%1$s. Dodirnite za postavljanje vibracije. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
     <string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Dodirnite da isključite zvuk. Zvukovi usluga pristupačnosti mogu biti isključeni."</string>
-    <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Prikazane kontrole jačine zvuka za: %s. Prevucite prema gore za odbacivanje."</string>
-    <string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrole jačine zvuka sakrivene"</string>
     <string name="system_ui_tuner" msgid="708224127392452018">"Podešavač za korisničko sučelje sistema"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Prikaži ugrađeni postotak baterije"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Prikazuje postotak nivoa baterije unutar ikone na statusnoj traci kada se baterija ne puni"</string>
@@ -488,24 +469,19 @@
     <string name="block" msgid="2734508760962682611">"Blokiraj sva obavještenja"</string>
     <string name="do_not_silence" msgid="6878060322594892441">"Nemoj utišati"</string>
     <string name="do_not_silence_block" msgid="4070647971382232311">"Nemoj utišati ili blokirati"</string>
-    <string name="tuner_full_importance_settings" msgid="3207312268609236827">"Kontrole obavještenja o napajanju"</string>
-    <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>
-    <string name="user_unspecified_importance" msgid="361613856933432117">"Značaj: Automatski"</string>
-    <string name="blocked_importance" msgid="5035073235408414397">"Značaj: Nivo 0"</string>
-    <string name="min_importance" msgid="560779348928574878">"Značaj: Nivo 1"</string>
-    <string name="low_importance" msgid="7571498511534140">"Značaj: Nivo 2"</string>
-    <string name="default_importance" msgid="7609889614553354702">"Značaj: Nivo 3"</string>
-    <string name="high_importance" msgid="3441537905162782568">"Značaj: Nivo 4"</string>
-    <string name="max_importance" msgid="4880179829869865275">"Značaj: Nivo 5"</string>
-    <string name="notification_importance_user_unspecified" msgid="2868359605125272874">"Aplikacija određuje važnost svakog obavještenja."</string>
-    <string name="notification_importance_blocked" msgid="4237497046867398057">"Nikad ne prikazuj obavještenja iz ove aplikacije"</string>
-    <string name="notification_importance_min" msgid="7844224511187027155">"Bez prekidanja prikaza cijelog ekrana, izvirivanja, zvuka ili vibracije. Sakriti sa ekrana za zaključavanje i statusne trake."</string>
-    <string name="notification_importance_low" msgid="7950291702044409847">"Bez prekidanja prikaza cijelog ekrana, izvirivanja, zvuka ili vibracije."</string>
-    <string name="notification_importance_default" msgid="5924405820269074915">"Bez izvirivanja ili prekidanja prikaza cijelog ekrana."</string>
-    <string name="notification_importance_high" msgid="1729480727023990427">"Uvijek izviruj. Bez prekidanja prikaza cijelog ekrana."</string>
-    <string name="notification_importance_max" msgid="2508384624461849111">"Uvijek izviruj i dopusti prekid prikaza cijelog ekrana."</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletne postavke za određivanje značaja"</string>
+    <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
+    <string name="min_importance" msgid="1901894910809414782">"Minimalni značaj"</string>
+    <string name="low_importance" msgid="4109929986107147930">"Mali značaj"</string>
+    <string name="default_importance" msgid="8192107689995742653">"Normalan značaj"</string>
+    <string name="high_importance" msgid="1527066195614050263">"Visok značaj"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Hitan značaj"</string>
+    <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikada ne prikazuj ova obavještenja"</string>
+    <string name="notification_importance_min" msgid="1938190340516905748">"Nečujno prikaži na dnu spiska obavještenja"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Nečujno prikaži ova obavještenja"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite zvuk na ovim obavještenjima"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Kratko prikaži na ekranu i dozvoli zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikaži na vrhu liste obavještenja, kratko prikaži na ekranu i dozvoli zvuk"</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>
@@ -604,7 +580,7 @@
     <string name="keycode_description" msgid="1403795192716828949">"Dugmad za kodiranje tipki omogućavaju da se tipke sa tipkovnice dodaju u navigacionu traku. Kada se pritisnu, oni oponašaju izabranu tipku tastature. Kao prvo, tipka mora biti izabrana za dugme, a nakon toga se bira slika koja će biti prikazana na njemu."</string>
     <string name="select_keycode" msgid="7413765103381924584">"Odaberite dugme na tastaturi"</string>
     <string name="preview" msgid="9077832302472282938">"Pregledaj"</string>
-    <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da dodate polja"</string>
+    <string name="drag_to_add_tiles" msgid="7058945779098711293">"Povucite da biste dodali polja"</string>
     <string name="drag_to_remove_tiles" msgid="3361212377437088062">"Prevucite ovdje za uklanjanje"</string>
     <string name="qs_edit" msgid="2232596095725105230">"Uredi"</string>
     <string name="tuner_time" msgid="6572217313285536011">"Vrijeme"</string>
@@ -620,16 +596,10 @@
   </string-array>
     <string name="other" msgid="4060683095962566764">"Ostalo"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik ekrana"</string>
-    <string name="accessibility_action_divider_left_full" msgid="2801570521881574972">"Lijevo cijeli ekran"</string>
-    <string name="accessibility_action_divider_left_70" msgid="3612060638991687254">"Lijevo 70%"</string>
-    <string name="accessibility_action_divider_left_50" msgid="1248083470322193075">"Lijevo 50%"</string>
-    <string name="accessibility_action_divider_left_30" msgid="543324403127069386">"Lijevo 30%"</string>
-    <string name="accessibility_action_divider_right_full" msgid="4639381073802030463">"Desno cijeli ekran"</string>
-    <string name="accessibility_action_divider_top_full" msgid="5357010904067731654">"Gore cijeli ekran"</string>
-    <string name="accessibility_action_divider_top_70" msgid="5090779195650364522">"Gore 70%"</string>
-    <string name="accessibility_action_divider_top_50" msgid="6385859741925078668">"Gore 50%"</string>
-    <string name="accessibility_action_divider_top_30" msgid="6201455163864841205">"Gore 30%"</string>
-    <string name="accessibility_action_divider_bottom_full" msgid="301433196679548001">"Dole cijeli ekran"</string>
+    <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomjeri dolje"</string>
+    <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Pomjeri lijevo"</string>
+    <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"Pomjeri desno"</string>
     <string name="accessibility_qs_edit_tile_label" msgid="8374924053307764245">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>, <xliff:g id="TILE_NAME">%2$s</xliff:g>. Dvaput dodirnite za uređivanje."</string>
     <string name="accessibility_qs_edit_add_tile_label" msgid="8133209638023882667">"<xliff:g id="TILE_NAME">%1$s</xliff:g> Dvaput dodirnite za dodavanje."</string>
     <string name="accessibility_qs_edit_position_label" msgid="5055306305919289819">"Pozicija <xliff:g id="POSITION">%1$d</xliff:g>. Dvaput dodirnite za odabir."</string>
@@ -639,17 +609,9 @@
     <string name="accessibility_qs_edit_tile_removed" msgid="8584304916627913440">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je uklonjen"</string>
     <string name="accessibility_qs_edit_tile_moved" msgid="4343693412689365038">"<xliff:g id="TILE_NAME">%1$s</xliff:g> je premješten na poziciju <xliff:g id="POSITION">%2$d</xliff:g>"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="8073587401747016103">"Uređivanje brzih postavki"</string>
-    <string name="accessibility_desc_notification_icon" msgid="8352414185263916335">"<xliff:g id="ID_1">%1$s</xliff:g> obavještenje: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Aplikacija možda neće raditi na podijeljenom ekranu"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikacija ne podržava dijeljenje ekrana."</string>
-    <string name="accessibility_quick_settings_settings" msgid="6132460890024942157">"Otvori postavke."</string>
-    <string name="accessibility_quick_settings_expand" msgid="2375165227880477530">"Otvoriti brze postavke."</string>
-    <string name="accessibility_quick_settings_collapse" msgid="1792625797142648105">"Zatvoriti brze postavke."</string>
-    <string name="accessibility_quick_settings_alarm_set" msgid="1863000242431528676">"Alarm postavljen."</string>
-    <string name="accessibility_quick_settings_user" msgid="1567445362870421770">"Prijavljeni ste kao <xliff:g id="ID_1">%s</xliff:g>"</string>
-    <string name="accessibility_quick_settings_no_internet" msgid="31890692343084075">"Nema internet veze."</string>
-    <string name="accessibility_quick_settings_open_details" msgid="4230931801728005194">"Otvori detalje."</string>
-    <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"Otvori postavke za: <xliff:g id="ID_1">%s</xliff:g>."</string>
-    <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Urediti raspored postavki."</string>
-    <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Stranica <xliff:g id="ID_1">%1$d</xliff:g> od <xliff:g id="ID_2">%2$d</xliff:g>"</string>
+    <string name="accessibility_quick_settings_expand" msgid="4982484435775933070">"Proširite brze postavke."</string>
+    <!-- no translation found for accessibility_quick_settings_page (5032979051755200721) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bs-rBA/strings_tv.xml b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
index df27da3..65c0982 100644
--- a/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
+++ b/packages/SystemUI/res/values-bs-rBA/strings_tv.xml
@@ -20,12 +20,14 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="pip_close" msgid="3480680679023423574">"Zatvori PIP"</string>
-    <string name="pip_fullscreen" msgid="8604643018538487816">"Cijeli ekran"</string>
-    <string name="pip_play" msgid="674145557658227044">"Pokreni"</string>
-    <string name="pip_pause" msgid="8412075640017218862">"Pauziraj"</string>
+    <!-- no translation found for pip_fullscreen (8604643018538487816) -->
+    <skip />
+    <!-- no translation found for pip_play (674145557658227044) -->
+    <skip />
+    <!-- no translation found for pip_pause (8412075640017218862) -->
+    <skip />
     <string name="pip_hold_home" msgid="340086535668778109">"Za kontr. PIP držite "<b>"HOME"</b></string>
-    <string name="pip_onboarding_title" msgid="7850436557670253991">"Slika u slici"</string>
-    <string name="pip_onboarding_description" msgid="4028124563309465267">"Ovim videozapis ostaje prikazan sve dok pokrenete sljedeći. Pritisnite i držite "<b>" POČETAK "</b>" za kontrole PIP-a."</string>
+    <string name="pip_onboarding_description" msgid="2882896641362814195">"Za kontrolu PIP, pritisnite i držite dugme POČETAK"</string>
     <string name="pip_onboarding_button" msgid="3957426748484904611">"Jasno mi je"</string>
     <string name="recents_tv_dismiss" msgid="3555093879593377731">"Odbaci"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index cd08f34..6a57c13 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -580,7 +580,7 @@
     <string name="accessibility_data_saver_on" msgid="8454111686783887148">"Reducir datos está activada"</string>
     <string name="accessibility_data_saver_off" msgid="8841582529453005337">"Reducir datos está desactivada"</string>
     <string name="switch_bar_on" msgid="1142437840752794229">"Activado"</string>
-    <string name="switch_bar_off" msgid="8803270596930432874">"Desactivado"</string>
+    <string name="switch_bar_off" msgid="8803270596930432874">"Desactivar"</string>
     <string name="nav_bar" msgid="1993221402773877607">"Barra de navegación"</string>
     <string name="start" msgid="6873794757232879664">"Iniciar"</string>
     <string name="center" msgid="4327473927066010960">"Centro"</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 6c5a313..7e63cbf 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -94,8 +94,6 @@
     <dimen name="navigation_key_width">128dp</dimen>
     <dimen name="navigation_key_padding">25dp</dimen>
 
-    <dimen name="qs_expand_margin">0dp</dimen>
-
     <!-- Keyboard shortcuts helper -->
     <dimen name="ksh_layout_width">488dp</dimen>
 
diff --git a/packages/SystemUI/res/values-w550dp-land/dimens.xml b/packages/SystemUI/res/values-w550dp-land/dimens.xml
index 4160c83..eaca9d7 100644
--- a/packages/SystemUI/res/values-w550dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-w550dp-land/dimens.xml
@@ -18,6 +18,4 @@
 <resources>
     <!-- Standard notification width + gravity -->
     <dimen name="notification_panel_width">544dp</dimen>
-
-    <dimen name="qs_expand_margin">32dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index e98309e..a55a8fd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,6 +103,11 @@
         wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location
     </string>
 
+    <!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
+    <string name="quick_settings_tiles_stock" translatable="false">
+        wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night
+    </string>
+
     <!-- The tiles to display in QuickSettings -->
     <string name="quick_settings_tiles" translatable="false">default</string>
 
@@ -265,4 +270,3 @@
     <bool name="quick_settings_show_date">false</bool>
 
 </resources>
-
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 2a4752a..eef5717 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -130,7 +130,7 @@
     <dimen name="close_handle_underlap">32dp</dimen>
 
     <!-- Height of the status bar header bar -->
-    <dimen name="status_bar_header_height">80dp</dimen>
+    <dimen name="status_bar_header_height">104dp</dimen>
 
     <!-- Height of the status bar header bar when expanded -->
     <dimen name="status_bar_header_height_expanded">116dp</dimen>
@@ -172,8 +172,6 @@
     <dimen name="qs_tile_margin_top">16dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
-    <dimen name="qs_date_anim_translation">32dp</dimen>
-    <dimen name="qs_date_alarm_anim_translation">22dp</dimen>
     <dimen name="qs_date_collapsed_text_size">14sp</dimen>
     <dimen name="qs_date_text_size">16sp</dimen>
     <dimen name="qs_header_gear_translation">16dp</dimen>
@@ -202,7 +200,6 @@
     <dimen name="qs_detail_margin_top">28dp</dimen>
     <dimen name="qs_data_usage_text_size">14sp</dimen>
     <dimen name="qs_data_usage_usage_text_size">36sp</dimen>
-    <dimen name="qs_expand_margin">0dp</dimen>
     <dimen name="qs_battery_padding">2dp</dimen>
     <dimen name="qs_detail_items_padding_top">4dp</dimen>
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 53c2233..9a36aca 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -23,6 +23,9 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.R;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.KeyguardBouncer;
 import com.android.systemui.statusbar.phone.NotificationIconAreaController;
@@ -115,4 +118,8 @@
     public <T> T createInstance(Class<T> classType) {
         return null;
     }
+
+    public AssistManager createAssistManager(BaseStatusBar bar, Context context) {
+        return new AssistManager(bar, context);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index a0aeb2f..a5e771f 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -30,6 +30,7 @@
 import com.android.internal.app.AssistUtils;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 
@@ -103,6 +104,10 @@
         }
     }
 
+    protected boolean shouldShowOrb() {
+        return true;
+    }
+
     public void startAssist(Bundle args) {
         final ComponentName assistComponent = getAssistInfo();
         if (assistComponent == null) {
@@ -110,7 +115,7 @@
         }
 
         final boolean isService = assistComponent.equals(getVoiceInteractorComponentName());
-        if (!isService || !isVoiceSessionRunning()) {
+        if (!isService || (!isVoiceSessionRunning() && shouldShowOrb())) {
             showOrb(assistComponent, isService);
             mView.postDelayed(mHideRunnable, isService
                     ? TIMEOUT_SERVICE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index cad7f64..3bbcf6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -360,7 +360,7 @@
             mSwitchingUser = false;
             if (userId != UserHandle.USER_SYSTEM) {
                 UserInfo info = UserManager.get(mContext).getUserInfo(userId);
-                if (info != null && info.isGuest()) {
+                if (info != null && (info.isGuest() || info.isDemo())) {
                     // If we just switched to a guest, try to dismiss keyguard.
                     dismiss();
                 }
@@ -399,8 +399,7 @@
             sendUserPresentBroadcast();
             synchronized (KeyguardViewMediator.this) {
                 // If system user is provisioned, we might want to lock now to avoid showing launcher
-                if (UserManager.isSplitSystemUser()
-                        && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM) {
+                if (mustNotUnlockCurrentUser()) {
                     doKeyguardLocked(null);
                 }
             }
@@ -599,7 +598,6 @@
                 return KeyguardSecurityView.PROMPT_REASON_WRONG_CREDENTIAL;
             }
 
-
             return KeyguardSecurityView.PROMPT_REASON_NONE;
         }
     };
@@ -608,6 +606,11 @@
         mPM.userActivity(SystemClock.uptimeMillis(), false);
     }
 
+    boolean mustNotUnlockCurrentUser() {
+        return (UserManager.isSplitSystemUser() || UserManager.isDeviceInDemoMode(mContext))
+                && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM;
+    }
+
     private void setupLocked() {
         mPM = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mWM = WindowManagerGlobal.getWindowManagerService();
@@ -1176,8 +1179,7 @@
         }
 
         // In split system user mode, we never unlock system user.
-        if (!UserManager.isSplitSystemUser()
-                || KeyguardUpdateMonitor.getCurrentUser() != UserHandle.USER_SYSTEM
+        if (!mustNotUnlockCurrentUser()
                 || !mUpdateMonitor.isDeviceProvisioned()) {
 
             // if the setup wizard hasn't run yet, don't show
@@ -1615,8 +1617,7 @@
         synchronized (KeyguardViewMediator.this) {
             if (DEBUG) Log.d(TAG, "handleHide");
 
-            if (UserManager.isSplitSystemUser()
-                    && KeyguardUpdateMonitor.getCurrentUser() == UserHandle.USER_SYSTEM) {
+            if (mustNotUnlockCurrentUser()) {
                 // In split system user mode, we never unlock system user. The end user has to
                 // switch to another user.
                 // TODO: We should stop it early by disabling the swipe up flow. Right now swipe up
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 51efbf0..0549afa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -57,6 +58,7 @@
     private boolean mIsVisible;
     private boolean mIsIconVisible;
     private int mFooterTextId;
+    private int mFooterIconId;
 
     public QSFooter(QSPanel qsPanel, Context context) {
         mRootView = LayoutInflater.from(context)
@@ -64,6 +66,7 @@
         mRootView.setOnClickListener(this);
         mFooterText = (TextView) mRootView.findViewById(R.id.footer_text);
         mFooterIcon = (ImageView) mRootView.findViewById(R.id.footer_icon);
+        mFooterIconId = R.drawable.ic_qs_vpn;
         mContext = context;
         mMainHandler = new Handler();
     }
@@ -118,6 +121,14 @@
             mIsVisible = true;
         } else {
             mFooterTextId = R.string.vpn_footer;
+            // Update the VPN footer icon, if needed.
+            int footerIconId = (mSecurityController.isVpnBranded()
+                ? R.drawable.ic_qs_branded_vpn
+                : R.drawable.ic_qs_vpn);
+            if (mFooterIconId != footerIconId) {
+                mFooterIcon.setImageResource(footerIconId);
+                mFooterIconId = footerIconId;
+            }
             mIsVisible = mIsIconVisible;
         }
         mMainHandler.post(mUpdateDisplayState);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 6945176..8148844 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -104,8 +104,6 @@
                 R.layout.qs_paged_tile_layout, this, false);
         mTileLayout.setListening(mListening);
         addView((View) mTileLayout);
-        findViewById(android.R.id.edit).setOnClickListener(view ->
-                mHost.startRunnableDismissingKeyguard(() -> showEdit(view)));
     }
 
     public boolean isShowingCustomize() {
@@ -354,7 +352,7 @@
     }
 
 
-    private void showEdit(final View v) {
+    public void showEdit(final View v) {
         v.post(new Runnable() {
             @Override
             public void run() {
@@ -362,8 +360,8 @@
                     if (!mCustomizePanel.isCustomizing()) {
                         int[] loc = new int[2];
                         v.getLocationInWindow(loc);
-                        int x = loc[0];
-                        int y = loc[1];
+                        int x = loc[0] + v.getWidth() / 2;
+                        int y = loc[1] + v.getHeight() / 2;
                         mCustomizePanel.show(x, y);
                     }
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index b28d0f2..2a0e6b3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -141,12 +141,11 @@
     };
 
     public int getNumQuickTiles(Context context) {
-        return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
+        return TunerService.get(context).getValue(NUM_QUICK_TILES, 6);
     }
 
     private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
 
-        private final Space mEndSpacer;
         protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
         private boolean mListening;
 
@@ -156,25 +155,6 @@
             setClipToPadding(false);
             setGravity(Gravity.CENTER_VERTICAL);
             setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-
-            mEndSpacer = new Space(context);
-            mEndSpacer.setLayoutParams(generateLayoutParams());
-            updateDownArrowMargin();
-            addView(mEndSpacer);
-            setOrientation(LinearLayout.HORIZONTAL);
-        }
-
-        @Override
-        protected void onConfigurationChanged(Configuration newConfig) {
-            super.onConfigurationChanged(newConfig);
-            updateDownArrowMargin();
-        }
-
-        private void updateDownArrowMargin() {
-            LayoutParams params = (LayoutParams) mEndSpacer.getLayoutParams();
-            params.setMarginStart(mContext.getResources().getDimensionPixelSize(
-                    R.dimen.qs_expand_margin));
-            mEndSpacer.setLayoutParams(params);
         }
 
         @Override
@@ -188,11 +168,11 @@
 
         @Override
         public void addTile(TileRecord tile) {
-            addView(tile.tileView, getChildCount() - 1 /* Leave icon at end */,
-                    generateLayoutParams());
-            // Add a spacer.
-            addView(new Space(mContext), getChildCount() - 1 /* Leave icon at end */,
-                    generateSpaceParams());
+            if (getChildCount() != 0) {
+                // Add a spacer.
+                addView(new Space(mContext), getChildCount(), generateSpaceParams());
+            }
+            addView(tile.tileView, getChildCount(), generateLayoutParams());
             mRecords.add(tile);
             tile.tile.setListening(this, mListening);
         }
@@ -217,8 +197,10 @@
             int childIndex = getChildIndex(tile.tileView);
             // Remove the tile.
             removeViewAt(childIndex);
-            // Remove its spacer as well.
-            removeViewAt(childIndex);
+            if (getChildCount() != 0) {
+                // Remove its spacer as well.
+                removeViewAt(childIndex);
+            }
             mRecords.remove(tile);
             tile.tile.setListening(this, false);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 8ec6a2f..b38dd17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -55,8 +55,7 @@
     }
 
     private void addSystemTiles(final QSTileHost host) {
-        String possible = mContext.getString(R.string.quick_settings_tiles_default)
-                + ",hotspot,inversion,saver,work,cast,night";
+        String possible = mContext.getString(R.string.quick_settings_tiles_stock);
         String[] possibleTiles = possible.split(",");
         final Handler qsHandler = new Handler(host.getLooper());
         final Handler mainHandler = new Handler(Looper.getMainLooper());
@@ -141,9 +140,16 @@
             PackageManager pm = mContext.getPackageManager();
             List<ResolveInfo> services = pm.queryIntentServicesAsUser(
                     new Intent(TileService.ACTION_QS_TILE), 0, ActivityManager.getCurrentUser());
+            String stockTiles = mContext.getString(R.string.quick_settings_tiles_stock);
             for (ResolveInfo info : services) {
                 String packageName = info.serviceInfo.packageName;
                 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
+
+                // Don't include apps that are a part of the default tile set.
+                if (stockTiles.contains(componentName.flattenToString())) {
+                    continue;
+                }
+
                 final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
                 String spec = CustomTile.toSpec(componentName);
                 State state = getState(params[0], spec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index 79e06c6..9211562 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -72,7 +72,6 @@
     private static final String TAG = KeyboardShortcuts.class.getSimpleName();
     private static final Object sLock = new Object();
     private static KeyboardShortcuts sInstance;
-    private static boolean sIsShowing;
 
     private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
     private final SparseArray<String> mModifierNames = new SparseArray<>();
@@ -131,13 +130,12 @@
                 dismiss();
             }
             getInstance(context).showKeyboardShortcuts(deviceId);
-            sIsShowing = true;
         }
     }
 
     public static void toggle(Context context, int deviceId) {
         synchronized (sLock) {
-            if (sIsShowing) {
+            if (isShowing()) {
                 dismiss();
             } else {
                 show(context, deviceId);
@@ -151,10 +149,14 @@
                 sInstance.dismissKeyboardShortcuts();
                 sInstance = null;
             }
-            sIsShowing = false;
         }
     }
 
+    private static boolean isShowing() {
+        return sInstance != null && sInstance.mKeyboardShortcutsDialog != null
+                && sInstance.mKeyboardShortcutsDialog.isShowing();
+    }
+
     private void loadResources(Context context) {
         mSpecialCharacterNames.put(
                 KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 2b59c68..a2ad46a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -67,6 +67,8 @@
 
     private boolean mNoSimsVisible = false;
     private boolean mVpnVisible = false;
+    private int mVpnIconId = 0;
+    private int mLastVpnIconId = -1;
     private boolean mEthernetVisible = false;
     private int mEthernetIconId = 0;
     private int mLastEthernetIconId = -1;
@@ -164,6 +166,7 @@
         mSC = sc;
         mSC.addCallback(this);
         mVpnVisible = mSC.isVpnEnabled();
+        mVpnIconId = currentVpnIconId(mSC.isVpnBranded());
     }
 
     @Override
@@ -241,6 +244,7 @@
             @Override
             public void run() {
                 mVpnVisible = mSC.isVpnEnabled();
+                mVpnIconId = currentVpnIconId(mSC.isVpnBranded());
                 apply();
             }
         });
@@ -428,6 +432,15 @@
         if (mWifiGroup == null) return;
 
         mVpn.setVisibility(mVpnVisible ? View.VISIBLE : View.GONE);
+        if (mVpnVisible) {
+            if (mLastVpnIconId != mVpnIconId) {
+                setIconForView(mVpn, mVpnIconId);
+                mLastVpnIconId = mVpnIconId;
+            }
+            mVpn.setVisibility(View.VISIBLE);
+        } else {
+            mVpn.setVisibility(View.GONE);
+        }
         if (DEBUG) Log.d(TAG, String.format("vpn: %s", mVpnVisible ? "VISIBLE" : "GONE"));
 
         if (mEthernetVisible) {
@@ -556,6 +569,10 @@
         v.setImageTintList(ColorStateList.valueOf(tint));
     }
 
+    private int currentVpnIconId(boolean isBranded) {
+        return isBranded ? R.drawable.stat_sys_branded_vpn : R.drawable.stat_sys_vpn_ic;
+    }
+
     private class PhoneState {
         private final int mSubId;
         private boolean mMobileVisible = false;
@@ -677,4 +694,3 @@
         }
     }
 }
-
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 30d24ff..b5a48a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -14,11 +14,10 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.graphics.drawable.Drawable;
 import android.view.View;
-import android.widget.ImageView;
-
-import com.android.systemui.statusbar.policy.KeyButtonView;
 
 import java.util.ArrayList;
 
@@ -65,9 +64,9 @@
             view.setVisibility(mVisibility);
         }
         if (mImageResource > 0) {
-            ((ImageView) view).setImageResource(mImageResource);
+            ((ButtonInterface) view).setImageResource(mImageResource);
         } else if (mImageDrawable != null) {
-            ((ImageView) view).setImageDrawable(mImageDrawable);
+            ((ButtonInterface) view).setImageDrawable(mImageDrawable);
         }
     }
 
@@ -88,7 +87,7 @@
         mImageResource = -1;
         final int N = mViews.size();
         for (int i = 0; i < N; i++) {
-            ((ImageView) mViews.get(i)).setImageDrawable(mImageDrawable);
+            ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
         }
     }
 
@@ -97,7 +96,7 @@
         mImageDrawable = null;
         final int N = mViews.size();
         for (int i = 0; i < N; i++) {
-            ((ImageView) mViews.get(i)).setImageResource(mImageResource);
+            ((ButtonInterface) mViews.get(i)).setImageResource(mImageResource);
         }
     }
 
@@ -114,7 +113,7 @@
         // This seems to be an instantaneous thing, so not going to persist it.
         final int N = mViews.size();
         for (int i = 0; i < N; i++) {
-            ((KeyButtonView) mViews.get(i)).abortCurrentGesture();
+            ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
         }
     }
 
@@ -165,4 +164,15 @@
     public void setCurrentView(View currentView) {
         mCurrentView = currentView.findViewById(mId);
     }
+
+    /**
+     * Interface for ImageView button actions.
+     */
+    public interface ButtonInterface {
+        void setImageResource(@DrawableRes int resId);
+
+        void setImageDrawable(@Nullable Drawable drawable);
+
+        void abortCurrentGesture();
+    }
 }
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 2bee816..dd46b08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -26,7 +26,9 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.Space;
+
 import com.android.systemui.R;
+import com.android.systemui.SystemUIFactory;
 import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.tuner.TunerService;
 
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 5fab796..53fe6ce3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -380,10 +380,6 @@
                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
 
-        if (SLIPPERY_WHEN_DISABLED) {
-            setSlippery(disableHome && disableRecent && disableBack && disableSearch);
-        }
-
         ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
         if (navButtons != null) {
             LayoutTransition lt = navButtons.getLayoutTransition();
@@ -458,22 +454,6 @@
         }
     }
 
-    public void setSlippery(boolean newSlippery) {
-        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
-        if (lp != null) {
-            boolean oldSlippery = (lp.flags & WindowManager.LayoutParams.FLAG_SLIPPERY) != 0;
-            if (!oldSlippery && newSlippery) {
-                lp.flags |= WindowManager.LayoutParams.FLAG_SLIPPERY;
-            } else if (oldSlippery && !newSlippery) {
-                lp.flags &= ~WindowManager.LayoutParams.FLAG_SLIPPERY;
-            } else {
-                return;
-            }
-            WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
-            wm.updateViewLayout(this, lp);
-        }
-    }
-
     public void setMenuVisibility(final boolean show) {
         setMenuVisibility(show, false);
     }
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 de5e06c..376f724a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -765,7 +765,7 @@
             // no window manager? good luck with that
         }
 
-        mAssistManager = new AssistManager(this, context);
+        mAssistManager = SystemUIFactory.getInstance().createAssistManager(this, context);
 
         // figure out which pixel-format to use for the status bar.
         mPixelFormat = PixelFormat.OPAQUE;
@@ -1372,7 +1372,8 @@
                     | 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_SPLIT_TOUCH
+                    | WindowManager.LayoutParams.FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         // this will allow the navbar to run in an overlay on devices that support this
         if (ActivityManager.isHighEndGfx()) {
@@ -2578,8 +2579,6 @@
         }
 
         mExpandedVisible = true;
-        if (mNavigationBarView != null)
-            mNavigationBarView.setSlippery(true);
 
         // Expand the window to encompass the full screen in anticipation of the drag.
         // This is only possible to do atomically because the status bar is at the top of the screen!
@@ -2713,8 +2712,7 @@
         mNotificationPanel.closeQs();
 
         mExpandedVisible = false;
-        if (mNavigationBarView != null)
-            mNavigationBarView.setSlippery(false);
+
         visibilityChanged(false);
 
         // Shrink the window to the size of the status bar only
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index d9dd9e2..81c0d81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -217,6 +217,8 @@
             mSimState = IccCardConstants.State.ABSENT;
         } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) {
             mSimState = IccCardConstants.State.CARD_IO_ERROR;
+        } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED.equals(stateExtra)) {
+            mSimState = IccCardConstants.State.CARD_RESTRICTED;
         } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) {
             mSimState = IccCardConstants.State.READY;
         } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 8bb1f24..3688495 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -81,18 +81,16 @@
     protected MultiUserSwitch mMultiUserSwitch;
     private ImageView mMultiUserAvatar;
 
-    private float mDateTimeTranslation;
-    private float mDateTimeAlarmTranslation;
     private float mDateScaleFactor;
     protected float mGearTranslation;
 
     private TouchAnimator mSecondHalfAnimator;
     private TouchAnimator mFirstHalfAnimator;
     private TouchAnimator mDateSizeAnimator;
-    private TouchAnimator mAlarmTranslation;
     protected TouchAnimator mSettingsAlpha;
     private float mExpansionAmount;
     private QSTileHost mHost;
+    private View mEdit;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -104,6 +102,10 @@
 
         mEmergencyOnly = (TextView) findViewById(R.id.header_emergency_calls_only);
 
+        mEdit = findViewById(android.R.id.edit);
+        findViewById(android.R.id.edit).setOnClickListener(view ->
+                mHost.startRunnableDismissingKeyguard(() -> mQsPanel.showEdit(view)));
+
         mDateTimeAlarmGroup = (ViewGroup) findViewById(R.id.date_time_alarm_group);
         mDateTimeAlarmGroup.findViewById(R.id.empty_time_view).setVisibility(View.GONE);
         mDateTimeGroup = (ViewGroup) findViewById(R.id.date_time_group);
@@ -153,16 +155,11 @@
 
         mGearTranslation = mContext.getResources().getDimension(R.dimen.qs_header_gear_translation);
 
-        mDateTimeTranslation = mContext.getResources().getDimension(
-                R.dimen.qs_date_anim_translation);
-        mDateTimeAlarmTranslation = mContext.getResources().getDimension(
-                R.dimen.qs_date_alarm_anim_translation);
         float dateCollapsedSize = mContext.getResources().getDimension(
                 R.dimen.qs_date_collapsed_text_size);
         float dateExpandedSize = mContext.getResources().getDimension(
                 R.dimen.qs_date_text_size);
         mDateScaleFactor = dateExpandedSize / dateCollapsedSize;
-        updateDateTimePosition();
 
         mSecondHalfAnimator = new TouchAnimator.Builder()
                 .addFloat(mAlarmStatus, "alpha", 0, 1)
@@ -184,10 +181,9 @@
 
     protected void updateSettingsAnimator() {
         mSettingsAlpha = new TouchAnimator.Builder()
-                .addFloat(mSettingsContainer, "translationY", -mGearTranslation, 0)
+                .addFloat(mEdit, "translationY", -mGearTranslation, 0)
                 .addFloat(mMultiUserSwitch, "translationY", -mGearTranslation, 0)
-                .addFloat(mSettingsButton, "rotation", -90, 0)
-                .addFloat(mSettingsContainer, "alpha", 0, 1)
+                .addFloat(mEdit, "alpha", 0, 1)
                 .addFloat(mMultiUserSwitch, "alpha", 0, 1)
                 .setStartDelay(QSAnimator.EXPANDED_TILE_DELAY)
                 .build();
@@ -246,7 +242,6 @@
         mSecondHalfAnimator.setPosition(headerExpansionFraction);
         mFirstHalfAnimator.setPosition(headerExpansionFraction);
         mDateSizeAnimator.setPosition(headerExpansionFraction);
-        mAlarmTranslation.setPosition(headerExpansionFraction);
         mSettingsAlpha.setPosition(headerExpansionFraction);
 
         updateAlarmVisibilities();
@@ -267,15 +262,6 @@
         mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
     }
 
-    private void updateDateTimePosition() {
-        // This one has its own because we have to rebuild it every time the alarm state changes.
-        mAlarmTranslation = new TouchAnimator.Builder()
-                .addFloat(mDateTimeAlarmGroup, "translationY", 0, mAlarmShowing
-                        ? mDateTimeAlarmTranslation : mDateTimeTranslation)
-                .build();
-        mAlarmTranslation.setPosition(mExpansionAmount);
-    }
-
     public void setListening(boolean listening) {
         if (listening == mListening) {
             return;
@@ -287,7 +273,6 @@
 
     @Override
     public void updateEverything() {
-        updateDateTimePosition();
         updateVisibilities();
         setClickable(false);
     }
@@ -296,7 +281,6 @@
         updateAlarmVisibilities();
         mEmergencyOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly
                 ? View.VISIBLE : View.INVISIBLE);
-        mSettingsContainer.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
         mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
                 TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
         mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index c8c824a..d8b1a62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.annotation.DrawableRes;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -42,11 +44,12 @@
 import android.widget.ImageView;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ButtonDispatcher;
 
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
 
-public class KeyButtonView extends ImageView {
+public class KeyButtonView extends ImageView implements ButtonDispatcher.ButtonInterface {
 
     private int mContentDescriptionRes;
     private long mDownTime;
@@ -247,10 +250,21 @@
                 InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
     }
 
+    @Override
     public void abortCurrentGesture() {
         setPressed(false);
         mGestureAborted = true;
     }
+
+    @Override
+    public void setImageResource(@DrawableRes int resId) {
+        super.setImageResource(resId);
+    }
+
+    @Override
+    public void setImageDrawable(@Nullable Drawable drawable) {
+        super.setImageDrawable(drawable);
+    }
 }
 
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index a633241..b27bfcb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -810,7 +810,7 @@
 
     private SubscriptionInfo addSignalController(int id, int simSlotIndex) {
         SubscriptionInfo info = new SubscriptionInfo(id, "", simSlotIndex, "", "", 0, 0, "", 0,
-                null, 0, 0, "", SubscriptionManager.SIM_PROVISIONED);
+                null, 0, 0, "");
         mMobileSignalControllers.put(id, new MobileSignalController(mContext,
                 mConfig, mHasMobileDataFeature, mPhone, mCallbackHandler, this, info,
                 mSubDefaults, mReceiverHandler.getLooper()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
index a22f988..014afae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityController.java
@@ -23,6 +23,8 @@
     String getProfileOwnerName();
     boolean isVpnEnabled();
     boolean isVpnRestricted();
+    /** Whether the VPN app should use branded VPN iconography.  */
+    boolean isVpnBranded();
     String getPrimaryVpnName();
     String getProfileVpnName();
     void onUserSwitched(int newUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 5046456..07d3b59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -18,6 +18,8 @@
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
@@ -54,10 +56,13 @@
             .build();
     private static final int NO_NETWORK = -1;
 
+    private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED";
+
     private final Context mContext;
     private final ConnectivityManager mConnectivityManager;
     private final IConnectivityManager mConnectivityManagerService;
     private final DevicePolicyManager mDevicePolicyManager;
+    private final PackageManager mPackageManager;
     private final UserManager mUserManager;
 
     @GuardedBy("mCallbacks")
@@ -75,6 +80,7 @@
                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
         mConnectivityManagerService = IConnectivityManager.Stub.asInterface(
                 ServiceManager.getService(Context.CONNECTIVITY_SERVICE));
+        mPackageManager = context.getPackageManager();
         mUserManager = (UserManager)
                 context.getSystemService(Context.USER_SERVICE);
 
@@ -165,6 +171,21 @@
     }
 
     @Override
+    public boolean isVpnBranded() {
+        VpnConfig cfg = mCurrentVpns.get(mVpnUserId);
+        if (cfg == null) {
+            return false;
+        }
+
+        String packageName = getPackageNameForVpnConfig(cfg);
+        if (packageName == null) {
+            return false;
+        }
+
+        return isVpnPackageBranded(packageName);
+    }
+
+    @Override
     public void removeCallback(SecurityControllerCallback callback) {
         synchronized (mCallbacks) {
             if (callback == null) return;
@@ -245,6 +266,28 @@
         mCurrentVpns = vpns;
     }
 
+    private String getPackageNameForVpnConfig(VpnConfig cfg) {
+        if (cfg.legacy) {
+            return null;
+        }
+        return cfg.user;
+    }
+
+    private boolean isVpnPackageBranded(String packageName) {
+        boolean isBranded;
+        try {
+            ApplicationInfo info = mPackageManager.getApplicationInfo(packageName,
+                PackageManager.GET_META_DATA);
+            if (info == null || info.metaData == null || !info.isSystemApp()) {
+                return false;
+            }
+            isBranded = info.metaData.getBoolean(VPN_BRANDED_META_DATA, false);
+        } catch (NameNotFoundException e) {
+            return false;
+        }
+        return isBranded;
+    }
+
     private final NetworkCallback mNetworkCallback = new NetworkCallback() {
         @Override
         public void onAvailable(Network network) {
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index a1487e3..1dcb13c 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2212,12 +2212,52 @@
     // Notification group expansion state toggled by the expand affordance.
     ACTION_NOTIFICATION_GROUP_EXPANDER = 408;
 
+
     // Notification expansion state toggled by the expand gesture.
     ACTION_NOTIFICATION_GESTURE_EXPANDER = 409;
 
     // Notification group expansion state toggled by the expand gesture.
     ACTION_NOTIFICATION_GROUP_GESTURE_EXPANDER = 410;
 
+    // ---- End N Constants, all N constants go above this line ----
+
+    // ------- Begin N App Disambig Shade -----
+    // Application disambig shade opened or closed with a featured app.
+    // These are actually visibility events, but visible/hidden doesn't
+    // take a package, so these are being logged as actions.
+    // Package: Calling app on open, called app on close
+    ACTION_SHOW_APP_DISAMBIG_APP_FEATURED = 451;
+    ACTION_HIDE_APP_DISAMBIG_APP_FEATURED = 452;
+
+    // Application disambig shade opened or closed without a featured app.
+    // These are actually visibility events, but visible/hidden doesn't
+    // take a package, so these are being logged as actions.
+    // Package: Calling app on open, called app on close
+    ACTION_SHOW_APP_DISAMBIG_NONE_FEATURED = 453;
+    ACTION_HIDE_APP_DISAMBIG_NONE_FEATURED = 454;
+
+    // User opens in an app by pressing “Always” in the application disambig shade.
+    // Subtype: Index of selection
+    ACTION_APP_DISAMBIG_ALWAYS = 455;
+
+    // User opens in an app by pressing “Just Once” in the application disambig shade.
+    // Subtype: Index of selection
+    ACTION_APP_DISAMBIG_JUST_ONCE = 456;
+
+    // User opens in an app by tapping on its name in the application disambig shade.
+    // Subtype: Index of selection
+    ACTION_APP_DISAMBIG_TAP = 457;
+
+    // OPEN: Settings > Internal storage > Storage manager
+    // CATEGORY: SETTINGS
+    STORAGE_MANAGER_SETTINGS = 458;
+
+    // OPEN: Settings -> Gestures
+    // CATEGORY: SETTINGS
+    SETTINGS_GESTURES = 459;
+
+    // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 4e0ddd6..04a0990 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -29,6 +29,7 @@
 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -70,10 +71,12 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.AttributeSet;
+import android.util.LongSparseArray;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
+import android.util.SparseLongArray;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.Display;
@@ -732,8 +735,8 @@
     }
 
     @Override
-    public ParceledListSlice<RemoteViews> startListening(IAppWidgetHost callbacks,
-            String callingPackage, int hostId, int[] appWidgetIds, int[] updatedIds) {
+    public ParceledListSlice<PendingHostUpdate> startListening(IAppWidgetHost callbacks,
+            String callingPackage, int hostId, int[] appWidgetIds) {
         final int userId = UserHandle.getCallingUserId();
 
         if (DEBUG) {
@@ -753,18 +756,19 @@
             host.callbacks = callbacks;
 
             int N = appWidgetIds.length;
-            ArrayList<RemoteViews> outViews = new ArrayList<>(N);
-            RemoteViews rv;
-            int added = 0;
+            ArrayList<PendingHostUpdate> outUpdates = new ArrayList<>(N);
+
+            LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
             for (int i = 0; i < N; i++) {
-                rv = host.getPendingViewsForId(appWidgetIds[i]);
-                if (rv != null) {
-                    updatedIds[added] = appWidgetIds[i];
-                    outViews.add(rv);
-                    added++;
+                if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
+                    // We key the updates based on time, so that the values are sorted by time.
+                    int M = updatesMap.size();
+                    for (int j = 0; j < M; j++) {
+                        outUpdates.add(updatesMap.valueAt(j));
+                    }
                 }
             }
-            return new ParceledListSlice<>(outViews);
+            return new ParceledListSlice<>(outUpdates);
         }
     }
 
@@ -1804,6 +1808,15 @@
     }
 
     private void scheduleNotifyAppWidgetViewDataChanged(Widget widget, int viewId) {
+        if (viewId == ID_VIEWS_UPDATE || viewId == ID_PROVIDER_CHANGED) {
+            // A view id should never collide with these constants but a developer can call this
+            // method with a wrong id. In that case, ignore the call.
+            return;
+        }
+        long requestTime = SystemClock.uptimeMillis();
+        if (widget != null) {
+            widget.updateTimes.put(viewId, requestTime);
+        }
         if (widget == null || widget.host == null || widget.host.zombie
                 || widget.host.callbacks == null || widget.provider == null
                 || widget.provider.zombie) {
@@ -1813,6 +1826,7 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
+        args.arg3 = requestTime;
         args.argi1 = widget.appWidgetId;
         args.argi2 = viewId;
 
@@ -1823,9 +1837,10 @@
 
 
     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, int viewId) {
+            int appWidgetId, int viewId, long requestTime) {
         try {
             callbacks.viewDataChanged(appWidgetId, viewId);
+            host.lastWidgetUpdateTime = requestTime;
         } catch (RemoteException re) {
             // It failed; remove the callback. No need to prune because
             // we know that this host is still referenced by this instance.
@@ -1874,7 +1889,7 @@
     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
         long requestTime = SystemClock.uptimeMillis();
         if (widget != null) {
-            widget.lastUpdateTime = requestTime;
+            widget.updateTimes.put(ID_VIEWS_UPDATE, requestTime);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -1907,6 +1922,12 @@
     }
 
     private void scheduleNotifyProviderChangedLocked(Widget widget) {
+        long requestTime = SystemClock.uptimeMillis();
+        if (widget != null) {
+            // When the provider changes, reset everything else.
+            widget.updateTimes.clear();
+            widget.updateTimes.append(ID_PROVIDER_CHANGED, requestTime);
+        }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
             return;
@@ -1916,6 +1937,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = widget.provider.info;
+        args.arg4 = requestTime;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1924,9 +1946,10 @@
     }
 
     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, AppWidgetProviderInfo info) {
+            int appWidgetId, AppWidgetProviderInfo info, long requestTime) {
         try {
             callbacks.providerChanged(appWidgetId, info);
+            host.lastWidgetUpdateTime = requestTime;
         } catch (RemoteException re) {
             synchronized (mLock){
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3410,10 +3433,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
+                    long requestTime = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info);
+                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestTime);
                 } break;
 
                 case MSG_NOTIFY_PROVIDERS_CHANGED: {
@@ -3429,11 +3453,13 @@
                     SomeArgs args = (SomeArgs) message.obj;
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
+                    long requestTime = (Long) args.arg3;
                     final int appWidgetId = args.argi1;
                     final int viewId = args.argi2;
                     args.recycle();
 
-                    handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId);
+                    handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
+                            requestTime);
                 } break;
             }
         }
@@ -3772,20 +3798,41 @@
         }
 
         /**
-         * Returns the RemoveViews for the provided widget id if an update is pending
-         * for that widget.
+         * Adds all pending updates in {@param outUpdates} keys by the update time.
          */
-        public RemoteViews getPendingViewsForId(int appWidgetId) {
+        public boolean getPendingUpdatesForId(int appWidgetId,
+                LongSparseArray<PendingHostUpdate> outUpdates) {
             long updateTime = lastWidgetUpdateTime;
             int N = widgets.size();
             for (int i = 0; i < N; i++) {
                 Widget widget = widgets.get(i);
-                if (widget.appWidgetId == appWidgetId
-                        && widget.lastUpdateTime > updateTime) {
-                    return cloneIfLocalBinder(widget.getEffectiveViewsLocked());
+                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) {
+                            continue;
+                        }
+                        int id = widget.updateTimes.keyAt(j);
+                        final PendingHostUpdate update;
+                        switch (id) {
+                            case ID_PROVIDER_CHANGED:
+                                update = PendingHostUpdate.providerChanged(
+                                        appWidgetId, widget.provider.info);
+                                break;
+                            case ID_VIEWS_UPDATE:
+                                update = PendingHostUpdate.updateAppWidget(appWidgetId,
+                                        cloneIfLocalBinder(widget.getEffectiveViewsLocked()));
+                                break;
+                            default:
+                                update = PendingHostUpdate.viewDataChanged(appWidgetId, id);
+                        }
+                        outUpdates.put(time, update);
+                    }
+                    return true;
                 }
             }
-            return null;
+            return false;
         }
 
         @Override
@@ -3850,6 +3897,10 @@
         }
     }
 
+    // These can be any constants that would not collide with a resource id.
+    private static final int ID_VIEWS_UPDATE = 0;
+    private static final int ID_PROVIDER_CHANGED = 1;
+
     private static final class Widget {
         int appWidgetId;
         int restoredId;  // tracking & remapping any restored state
@@ -3858,7 +3909,8 @@
         RemoteViews maskedViews;
         Bundle options;
         Host host;
-        long lastUpdateTime;
+        // timestamps for various operations
+        SparseLongArray updateTimes = new SparseLongArray(2);
 
         @Override
         public String toString() {
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3eadb5c..d58f864 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -425,6 +425,24 @@
         return false;
     }
 
+    public int getState() {
+        if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
+                (!checkIfCallerIsForegroundUser())) {
+            Slog.w(TAG, "getState(): not allowed for non-active and non system user");
+            return BluetoothAdapter.STATE_OFF;
+        }
+
+        try {
+            mBluetoothLock.readLock().lock();
+            if (mBluetooth != null) return mBluetooth.getState();
+        } catch (RemoteException e) {
+            Slog.e(TAG, "getState()", e);
+        } finally {
+            mBluetoothLock.readLock().unlock();
+        }
+        return BluetoothAdapter.STATE_OFF;
+    }
+
     class ClientDeathRecipient implements IBinder.DeathRecipient {
         public void binderDied() {
             if (DBG) Slog.d(TAG, "Binder is dead -  unregister Ble App");
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index acf8009..1adefc4 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -797,6 +797,17 @@
         return new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId());
     }
 
+    // Used only for testing.
+    // TODO: Delete this and either:
+    // 1. Give Fake SettingsProvider the ability to send settings change notifications (requires
+    //    changing ContentResolver to make registerContentObserver non-final).
+    // 2. Give FakeSettingsProvider an alternative notification mechanism and have the test use it
+    //    by subclassing SettingsObserver.
+    @VisibleForTesting
+    void updateMobileDataAlwaysOn() {
+        mHandler.sendEmptyMessage(EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
+    }
+
     private void handleMobileDataAlwaysOn() {
         final boolean enable = (Settings.Global.getInt(
                 mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 0) == 1);
@@ -2161,9 +2172,11 @@
                             loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
                             break;
                         }
-                        setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
-                                nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
-                                (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+                        if (!nai.networkMisc.provisioningNotificationDisabled) {
+                            setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
+                                    nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(),
+                                    (PendingIntent)msg.obj, nai.networkMisc.explicitlySelected);
+                        }
                     }
                     break;
                 }
@@ -2564,6 +2577,7 @@
 
         PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
                 mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+
         setProvNotificationVisibleIntent(true, nai.network.netId, NotificationType.NO_INTERNET,
                 nai.networkInfo.getType(), nai.networkInfo.getExtraInfo(), pendingIntent, true);
     }
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index 1653db9..6f8edec 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -47,6 +47,7 @@
         final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
         final boolean wipeExternalStorage = intent.getBooleanExtra(
                 Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
+        final boolean forceWipe = intent.getBooleanExtra(Intent.EXTRA_FORCE_MASTER_CLEAR, false);
 
         Slog.w(TAG, "!!! FACTORY RESET !!!");
         // The reboot call is blocking, so we need to do it on another thread.
@@ -54,7 +55,7 @@
             @Override
             public void run() {
                 try {
-                    RecoverySystem.rebootWipeUserData(context, shutdown, reason);
+                    RecoverySystem.rebootWipeUserData(context, shutdown, reason, forceWipe);
                     Log.wtf(TAG, "Still running after master clear?!");
                 } catch (IOException e) {
                     Slog.e(TAG, "Can't perform master clear/factory reset", e);
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 2085f32..51037dd 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -26,6 +26,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.util.Slog;
@@ -145,6 +146,15 @@
                     "Only the Admin user is allowed to change OEM unlock state");
         }
     }
+
+    private void enforceFactoryResetAllowed() {
+        final boolean isOemUnlockRestricted = UserManager.get(mContext)
+                .hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET);
+        if (isOemUnlockRestricted) {
+            throw new SecurityException("OEM unlock is disallowed by DISALLOW_FACTORY_RESET");
+        }
+    }
+
     private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
         // skip over checksum
         inputStream.skipBytes(DIGEST_SIZE_BYTES);
@@ -437,14 +447,23 @@
         }
 
         @Override
-        public void setOemUnlockEnabled(boolean enabled) {
+        public void setOemUnlockEnabled(boolean enabled) throws SecurityException {
             // do not allow monkey to flip the flag
             if (ActivityManager.isUserAMonkey()) {
                 return;
             }
+
             enforceOemUnlockPermission();
             enforceIsAdmin();
 
+            // Do not allow oem unlock modification if it has been disallowed.
+            if (Settings.Global.getInt(getContext().getContentResolver(),
+                    Settings.Global.OEM_UNLOCK_DISALLOWED, 0) == 1) {
+                throw new SecurityException("OEM unlock has been disallowed.");
+            }
+            if (enabled) {
+                enforceFactoryResetAllowed();
+            }
             synchronized (mLock) {
                 doSetOemUnlockEnabledLocked(enabled);
                 computeAndWriteDigestLocked();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 32aeea8..37d214b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18680,8 +18680,9 @@
 
     /**
      * Decide based on the configuration whether we should shouw the ANR,
-     * crash, etc dialogs.  The idea is that if there is no affordnace to
-     * press the on-screen buttons, we shouldn't show the dialog.
+     * crash, etc dialogs.  The idea is that if there is no affordence to
+     * press the on-screen buttons, or the user experience would be more
+     * greatly impacted than the crash itself, we shouldn't show the dialog.
      *
      * A thought: SystemUI might also want to get told about this, the Power
      * dialog / global actions also might want different behaviors.
@@ -18690,9 +18691,10 @@
         final boolean inputMethodExists = !(config.keyboard == Configuration.KEYBOARD_NOKEYS
                                    && config.touchscreen == Configuration.TOUCHSCREEN_NOTOUCH
                                    && config.navigation == Configuration.NAVIGATION_NONAV);
-        final boolean uiIsNotCarType = !((config.uiMode & Configuration.UI_MODE_TYPE_MASK)
-                                    == Configuration.UI_MODE_TYPE_CAR);
-        return inputMethodExists && uiIsNotCarType && !inVrMode;
+        int modeType = config.uiMode & Configuration.UI_MODE_TYPE_MASK;
+        final boolean uiModeSupportsDialogs = (modeType != Configuration.UI_MODE_TYPE_CAR
+                && !(modeType == Configuration.UI_MODE_TYPE_WATCH && "user".equals(Build.TYPE)));
+        return inputMethodExists && uiModeSupportsDialogs && !inVrMode;
     }
 
     @Override
@@ -21157,6 +21159,11 @@
                 Slog.w(TAG, "No user info for user #" + targetUserId);
                 return false;
             }
+            if (!targetUserInfo.isDemo() && UserManager.isDeviceInDemoMode(mContext)) {
+                Slog.w(TAG, "Cannot switch to non-demo user #" + targetUserId
+                        + " when device is in demo mode");
+                return false;
+            }
             if (!targetUserInfo.supportsSwitchTo()) {
                 Slog.w(TAG, "Cannot switch to User #" + targetUserId + ": not supported");
                 return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0e4c9a4..1cf121c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4422,6 +4422,7 @@
         // Work Challenge is present) let startActivityInPackage handle the intercepting.
         if (!mService.mUserController.shouldConfirmCredentials(task.userId)
                 && task.getRootActivity() != null) {
+            mService.mActivityStarter.sendPowerHintForLaunchIfNeeded(true /* forceSend */);
             mActivityMetricsLogger.notifyActivityLaunching();
             mService.moveTaskToFrontLocked(task.taskId, 0, bOptions);
             mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT,
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 61b1317..b022c4f 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -102,6 +102,7 @@
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.PowerManagerInternal;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -172,6 +173,7 @@
     private boolean mNoAnimation;
     private boolean mKeepCurTransition;
     private boolean mAvoidMoveToFront;
+    private boolean mPowerHintSent;
 
     private IVoiceInteractionSession mVoiceSession;
     private IVoiceInteractor mVoiceInteractor;
@@ -210,6 +212,8 @@
         mKeepCurTransition = false;
         mAvoidMoveToFront = false;
 
+        mPowerHintSent = false;
+
         mVoiceSession = null;
         mVoiceInteractor = null;
     }
@@ -943,6 +947,20 @@
         return START_SUCCESS;
     }
 
+    void sendPowerHintForLaunchIfNeeded(boolean forceSend) {
+        // Trigger launch power hint if activity is not in the current task
+        final ActivityStack focusStack = mSupervisor.getFocusedStack();
+        final ActivityRecord curTop = (focusStack == null)
+            ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+        if ((forceSend || (!mPowerHintSent && curTop != null &&
+                curTop.task != null && mStartActivity != null &&
+                curTop.task != mStartActivity.task )) &&
+                mService.mLocalPowerManager != null) {
+            mService.mLocalPowerManager.powerHint(PowerManagerInternal.POWER_HINT_LAUNCH, 0);
+            mPowerHintSent = true;
+        }
+    }
+
     private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
             IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
             int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
@@ -1004,6 +1022,8 @@
                 }
             }
 
+            sendPowerHintForLaunchIfNeeded(false /* forceSend */);
+
             mReusedActivity = setTargetStackAndMoveToFrontIfNeeded(mReusedActivity);
 
             if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
@@ -1126,6 +1146,9 @@
         ActivityStack.logStartActivity(
                 EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
         mTargetStack.mLastPausedActivity = null;
+
+        sendPowerHintForLaunchIfNeeded(false /* forceSend */);
+
         mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
         if (mDoResume) {
             if (!mLaunchTaskBehind) {
diff --git a/services/core/java/com/android/server/am/RetailDemoModeService.java b/services/core/java/com/android/server/am/RetailDemoModeService.java
new file mode 100644
index 0000000..6a5ec96
--- /dev/null
+++ b/services/core/java/com/android/server/am/RetailDemoModeService.java
@@ -0,0 +1,318 @@
+/*
+ * 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.am;
+
+import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Slog;
+
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.R;
+import com.android.internal.widget.LockPatternUtils;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+import java.io.File;
+
+public class RetailDemoModeService extends SystemService {
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = RetailDemoModeService.class.getSimpleName();
+    private static final String DEMO_USER_NAME = "Demo";
+    private static final String ACTION_RESET_DEMO = "com.android.server.am.ACTION_RESET_DEMO";
+
+    private static final int MSG_TURN_SCREEN_ON = 0;
+    private static final int MSG_INACTIVITY_TIME_OUT = 1;
+    private static final int MSG_START_NEW_SESSION = 2;
+
+    private static final long SCREEN_WAKEUP_DELAY = 2500;
+    private static final long USER_INACTIVITY_TIMEOUT = 30000;
+
+    boolean mDeviceInDemoMode = false;
+    private ActivityManagerService mAms;
+    private NotificationManager mNm;
+    private UserManager mUm;
+    private PowerManager mPm;
+    private PowerManager.WakeLock mWakeLock;
+    Handler mHandler;
+    private ServiceThread mHandlerThread;
+    private PendingIntent mResetDemoPendingIntent;
+
+    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (!mDeviceInDemoMode) {
+                return;
+            }
+            switch (intent.getAction()) {
+                case Intent.ACTION_SCREEN_OFF:
+                    mHandler.removeMessages(MSG_TURN_SCREEN_ON);
+                    mHandler.sendEmptyMessageDelayed(MSG_TURN_SCREEN_ON, SCREEN_WAKEUP_DELAY);
+                    break;
+                case ACTION_RESET_DEMO:
+                    mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+                    break;
+            }
+        }
+    };
+
+    final class MainHandler extends Handler {
+
+        MainHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_TURN_SCREEN_ON:
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                    }
+                    mWakeLock.acquire();
+                    break;
+                case MSG_INACTIVITY_TIME_OUT:
+                    IPackageManager pm = AppGlobals.getPackageManager();
+                    int enabledState = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+                    String demoLauncherComponent = getContext().getResources()
+                            .getString(R.string.config_demoModeLauncherComponent);
+                    try {
+                        enabledState = pm.getComponentEnabledSetting(
+                                ComponentName.unflattenFromString(demoLauncherComponent),
+                            getActivityManager().getCurrentUser().id);
+                    } catch (RemoteException exc) {
+                        // XXX: shouldn't happen
+                    }
+                    if (enabledState == PackageManager.COMPONENT_ENABLED_STATE_DISABLED) {
+                        Slog.i(TAG, "Restarting session due to user inactivity timeout");
+                        sendEmptyMessage(MSG_START_NEW_SESSION);
+                    }
+                    break;
+                case MSG_START_NEW_SESSION:
+                    if (DEBUG) {
+                        Slog.d(TAG, "Switching to a new demo user");
+                    }
+                    removeMessages(MSG_START_NEW_SESSION);
+                    UserInfo demoUser = getUserManager().createUser(DEMO_USER_NAME,
+                            UserInfo.FLAG_DEMO | UserInfo.FLAG_EPHEMERAL);
+                    if (demoUser != null) {
+                        setupDemoUser(demoUser);
+                        getActivityManager().switchUser(demoUser.id);
+                    }
+                    break;
+            }
+        }
+    }
+
+    public RetailDemoModeService(Context context) {
+        super(context);
+    }
+
+    private Notification createResetNotification() {
+        return new Notification.Builder(getContext())
+                .setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
+                .setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
+                .setOngoing(true)
+                .setSmallIcon(R.drawable.platlogo)
+                .setShowWhen(false)
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setContentIntent(getResetDemoPendingIntent())
+                .setColor(getContext().getColor(R.color.system_notification_accent_color))
+                .build();
+    }
+
+    private PendingIntent getResetDemoPendingIntent() {
+        if (mResetDemoPendingIntent == null) {
+            Intent intent = new Intent(ACTION_RESET_DEMO);
+            mResetDemoPendingIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+        }
+        return mResetDemoPendingIntent;
+    }
+
+    void setupDemoUser(UserInfo userInfo) {
+        UserManager um = getUserManager();
+        UserHandle user = UserHandle.of(userInfo.id);
+        LockPatternUtils lockPatternUtils = new LockPatternUtils(getContext());
+        lockPatternUtils.setLockScreenDisabled(true, userInfo.id);
+        um.setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, user);
+        um.setUserRestriction(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, true, user);
+        um.setUserRestriction(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, true, user);
+        um.setUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER, true, user);
+        Settings.Secure.putIntForUser(getContext().getContentResolver(),
+                Settings.Secure.SKIP_FIRST_USE_HINTS, 1, userInfo.id);
+    }
+
+    private ActivityManagerService getActivityManager() {
+        if (mAms == null) {
+            mAms = (ActivityManagerService) ActivityManagerNative.getDefault();
+        }
+        return mAms;
+    }
+
+    private UserManager getUserManager() {
+        if (mUm == null) {
+            mUm = getContext().getSystemService(UserManager.class);
+        }
+        return mUm;
+    }
+
+    private void registerSettingsChangeObserver() {
+        final Uri deviceDemoModeUri = Settings.Global.getUriFor(Settings.Global.DEVICE_DEMO_MODE);
+        final Uri deviceProvisionedUri = Settings.Global.getUriFor(
+                Settings.Global.DEVICE_PROVISIONED);
+        final ContentResolver cr = getContext().getContentResolver();
+        final ContentObserver deviceDemoModeSettingObserver = new ContentObserver(mHandler) {
+            @Override
+            public void onChange(boolean selfChange, Uri uri, int userId) {
+                if (deviceDemoModeUri.equals(uri)) {
+                    mDeviceInDemoMode = UserManager.isDeviceInDemoMode(getContext());
+                    if (mDeviceInDemoMode) {
+                        mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+                    } else if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                    }
+                }
+                // If device is provisioned and left demo mode - run the cleanup in demo folder
+                if (!mDeviceInDemoMode && isDeviceProvisioned()) {
+                    // Run on the bg thread to not block the fg thread
+                    BackgroundThread.getHandler().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (!deleteDemoFolderContents()) {
+                                Slog.w(TAG, "Failed to delete demo folder contents");
+                            }
+                        }
+                    });
+                }
+            }
+        };
+        cr.registerContentObserver(deviceDemoModeUri, false, deviceDemoModeSettingObserver,
+                UserHandle.USER_SYSTEM);
+        cr.registerContentObserver(deviceProvisionedUri, false, deviceDemoModeSettingObserver,
+                UserHandle.USER_SYSTEM);
+    }
+
+    boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(
+                getContext().getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
+    private boolean deleteDemoFolderContents() {
+        File dir = Environment.getDataPreloadsDemoDirectory();
+        Slog.i(TAG, "Deleting contents of " + dir);
+        return FileUtils.deleteContents(dir);
+    }
+
+    private void registerBroadcastReceiver() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(ACTION_RESET_DEMO);
+        getContext().registerReceiver(mBroadcastReceiver, filter);
+    }
+
+    @Override
+    public void onStart() {
+        if (DEBUG) {
+            Slog.d(TAG, "Service starting up");
+        }
+        mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND,
+                false);
+        mHandlerThread.start();
+        mHandler = new MainHandler(mHandlerThread.getLooper());
+        publishLocalService(RetailDemoModeServiceInternal.class, mLocalService);
+    }
+
+    @Override
+    public void onBootPhase(int bootPhase) {
+        if (bootPhase != PHASE_THIRD_PARTY_APPS_CAN_START) {
+            return;
+        }
+        mPm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPm
+                .newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP, TAG);
+        mNm = NotificationManager.from(getContext());
+
+        if (UserManager.isDeviceInDemoMode(getContext())) {
+            mDeviceInDemoMode = true;
+            mHandler.sendEmptyMessage(MSG_START_NEW_SESSION);
+        }
+        registerSettingsChangeObserver();
+        registerBroadcastReceiver();
+    }
+
+    @Override
+    public void onSwitchUser(int userId) {
+        if (!mDeviceInDemoMode) {
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "onSwitchUser: " + userId);
+        }
+        UserInfo ui = getUserManager().getUserInfo(userId);
+        if (!ui.isDemo()) {
+            Slog.wtf(TAG, "Should not allow switch to non-demo user in demo mode");
+            return;
+        }
+        if (!mWakeLock.isHeld()) {
+            mWakeLock.acquire();
+        }
+        mNm.notifyAsUser(TAG, 1, createResetNotification(), UserHandle.of(userId));
+    }
+
+    public RetailDemoModeServiceInternal mLocalService = new RetailDemoModeServiceInternal() {
+        private static final long USER_ACTIVITY_DEBOUNCE_TIME = 2000;
+        private long mLastUserActivityTime = 0;
+
+        @Override
+        public void onUserActivity() {
+            if (!mDeviceInDemoMode) {
+                return;
+            }
+            long timeOfActivity = SystemClock.uptimeMillis();
+            if (timeOfActivity < mLastUserActivityTime + USER_ACTIVITY_DEBOUNCE_TIME) {
+                return;
+            }
+            mLastUserActivityTime = timeOfActivity;
+            mHandler.removeMessages(MSG_INACTIVITY_TIME_OUT);
+            mHandler.sendEmptyMessageDelayed(MSG_INACTIVITY_TIME_OUT, USER_INACTIVITY_TIMEOUT);
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java b/services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java
new file mode 100644
index 0000000..32de03a
--- /dev/null
+++ b/services/core/java/com/android/server/am/RetailDemoModeServiceInternal.java
@@ -0,0 +1,21 @@
+/*
+ * 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.am;
+
+public interface RetailDemoModeServiceInternal {
+    public void onUserActivity();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4380af3..2375d7a 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -224,6 +224,7 @@
 
     private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
         final int userId = uss.mHandle.getIdentifier();
+
         Slog.d(TAG, "Finishing user boot " + userId);
         synchronized (mService) {
             // Bail if we ended up with a stale user
diff --git a/services/core/java/com/android/server/am/UserSwitchingDialog.java b/services/core/java/com/android/server/am/UserSwitchingDialog.java
index 10e88e6..7022856 100644
--- a/services/core/java/com/android/server/am/UserSwitchingDialog.java
+++ b/services/core/java/com/android/server/am/UserSwitchingDialog.java
@@ -68,6 +68,12 @@
         String viewMessage;
         if (UserManager.isSplitSystemUser() && newUser.id == UserHandle.USER_SYSTEM) {
             viewMessage = res.getString(R.string.user_logging_out_message, oldUser.name);
+        } else if (UserManager.isDeviceInDemoMode(context)) {
+            if (oldUser.isDemo()) {
+                viewMessage = res.getString(R.string.demo_restarting_message);
+            } else {
+                viewMessage = res.getString(R.string.demo_starting_message);
+            }
         } else {
             viewMessage = res.getString(R.string.user_switching_message, newUser.name);
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index f4e1424..ddaebfa 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -66,7 +66,6 @@
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.WakeupMessage;
-import com.android.server.connectivity.NetworkAgentInfo;
 
 import java.io.IOException;
 import java.net.HttpURLConnection;
@@ -618,7 +617,7 @@
 
         @Override
         public void exit() {
-             removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
+            removeMessages(CMD_CAPTIVE_PORTAL_RECHECK);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index ffe8f75..43a0b91 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -745,9 +745,6 @@
             @Override
             public void onShortcutChanged(@NonNull String packageName,
                     @UserIdInt int userId) {
-                if (!ShortcutService.FEATURE_ENABLED) {
-                    return;
-                }
                 postToPackageMonitorHandler(() -> onShortcutChangedInner(packageName, userId));
             }
 
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index dfd6dfe..5126305 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4011,7 +4011,7 @@
         file.delete();
         removeCrossProfileIntentFiltersLPw(userId);
 
-        mRuntimePermissionsPersistence.onUserRemoved(userId);
+        mRuntimePermissionsPersistence.onUserRemovedLPw(userId);
 
         writePackageListLPr();
     }
@@ -5108,7 +5108,7 @@
             }
         }
 
-        private void onUserRemoved(int userId) {
+        private void onUserRemovedLPw(int userId) {
             // Make sure we do not
             mHandler.removeMessages(userId);
 
@@ -5119,6 +5119,9 @@
             for (SettingBase sb : mSharedUsers.values()) {
                 revokeRuntimePermissionsAndClearFlags(sb, userId);
             }
+
+            mDefaultPermissionsGranted.delete(userId);
+            mFingerprints.remove(userId);
         }
 
         private void revokeRuntimePermissionsAndClearFlags(SettingBase sb, int userId) {
diff --git a/services/core/java/com/android/server/pm/ShortcutLauncher.java b/services/core/java/com/android/server/pm/ShortcutLauncher.java
index 76d47a8..e667838 100644
--- a/services/core/java/com/android/server/pm/ShortcutLauncher.java
+++ b/services/core/java/com/android/server/pm/ShortcutLauncher.java
@@ -36,6 +36,8 @@
 
 /**
  * Launcher information used by {@link ShortcutService}.
+ *
+ * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
  */
 class ShortcutLauncher extends ShortcutPackageItem {
     private static final String TAG = ShortcutService.TAG;
@@ -80,26 +82,31 @@
      * Called when the new package can't receive the backup, due to signature or version mismatch.
      */
     @Override
-    protected void onRestoreBlocked(ShortcutService s) {
+    protected void onRestoreBlocked() {
         final ArrayList<PackageWithUser> pinnedPackages =
                 new ArrayList<>(mPinnedShortcuts.keySet());
         mPinnedShortcuts.clear();
         for (int i = pinnedPackages.size() - 1; i >= 0; i--) {
             final PackageWithUser pu = pinnedPackages.get(i);
-            s.getPackageShortcutsLocked(pu.packageName, pu.userId)
-                    .refreshPinnedFlags(s);
+            final ShortcutPackage p = mShortcutUser.getPackageShortcutsIfExists(pu.packageName);
+            if (p != null) {
+                p.refreshPinnedFlags();
+            }
         }
     }
 
     @Override
-    protected void onRestored(ShortcutService s) {
+    protected void onRestored() {
         // Nothing to do.
     }
 
-    public void pinShortcuts(@NonNull ShortcutService s, @UserIdInt int packageUserId,
+    public void pinShortcuts(@UserIdInt int packageUserId,
             @NonNull String packageName, @NonNull List<String> ids) {
         final ShortcutPackage packageShortcuts =
-                s.getPackageShortcutsLocked(packageName, packageUserId);
+                mShortcutUser.getPackageShortcutsIfExists(packageName);
+        if (packageShortcuts == null) {
+            return; // No need to instantiate.
+        }
 
         final PackageWithUser pu = PackageWithUser.of(packageUserId, packageName);
 
@@ -120,13 +127,14 @@
                 if (si == null) {
                     continue;
                 }
-                if (si.isDynamic() || (prevSet != null && prevSet.contains(id))) {
+                if (si.isDynamic() || si.isManifestShortcut()
+                        || (prevSet != null && prevSet.contains(id))) {
                     newSet.add(id);
                 }
             }
             mPinnedShortcuts.put(pu, newSet);
         }
-        packageShortcuts.refreshPinnedFlags(s);
+        packageShortcuts.refreshPinnedFlags();
     }
 
     /**
@@ -240,7 +248,7 @@
         return ret;
     }
 
-    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.println();
 
         pw.print(prefix);
@@ -252,7 +260,7 @@
         pw.print(getOwnerUserId());
         pw.println();
 
-        getPackageInfo().dump(s, pw, prefix + "  ");
+        getPackageInfo().dump(pw, prefix + "  ");
         pw.println();
 
         final int size = mPinnedShortcuts.size();
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index 151f61e..e0c28fa 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -20,15 +20,19 @@
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.PackageInfo;
 import android.content.pm.ShortcutInfo;
 import android.os.PersistableBundle;
 import android.text.format.Formatter;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
+import com.android.server.pm.ShortcutService.ShortcutOperation;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -38,12 +42,19 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Predicate;
 
 /**
  * Package information used by {@link ShortcutService}.
+ * User information used by {@link ShortcutService}.
+ *
+ * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
+ *
+ * TODO Max dynamic shortcuts cap should be per activity.
  */
 class ShortcutPackage extends ShortcutPackageItem {
     private static final String TAG = ShortcutService.TAG;
@@ -55,15 +66,18 @@
     private static final String TAG_CATEGORIES = "categories";
 
     private static final String ATTR_NAME = "name";
-    private static final String ATTR_DYNAMIC_COUNT = "dynamic-count";
     private static final String ATTR_CALL_COUNT = "call-count";
     private static final String ATTR_LAST_RESET = "last-reset";
     private static final String ATTR_ID = "id";
     private static final String ATTR_ACTIVITY = "activity";
     private static final String ATTR_TITLE = "title";
+    private static final String ATTR_TITLE_RES_ID = "titleid";
     private static final String ATTR_TEXT = "text";
+    private static final String ATTR_TEXT_RES_ID = "textid";
+    private static final String ATTR_DISABLED_MESSAGE = "dmessage";
+    private static final String ATTR_DISABLED_MESSAGE_RES_ID = "dmessageid";
     private static final String ATTR_INTENT = "intent";
-    private static final String ATTR_WEIGHT = "weight";
+    private static final String ATTR_RANK = "rank";
     private static final String ATTR_TIMESTAMP = "timestamp";
     private static final String ATTR_FLAGS = "flags";
     private static final String ATTR_ICON_RES = "icon-res";
@@ -80,11 +94,6 @@
     final private ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();
 
     /**
-     * # of dynamic shortcuts.
-     */
-    private int mDynamicShortcutCount = 0;
-
-    /**
      * # of times the package has called rate-limited APIs.
      */
     private int mApiCallCount;
@@ -98,17 +107,16 @@
 
     private long mLastKnownForegroundElapsedTime;
 
-    private ShortcutPackage(ShortcutService s, ShortcutUser shortcutUser,
+    private ShortcutPackage(ShortcutUser shortcutUser,
             int packageUserId, String packageName, ShortcutPackageInfo spi) {
         super(shortcutUser, packageUserId, packageName,
                 spi != null ? spi : ShortcutPackageInfo.newEmpty());
 
-        mPackageUid = s.injectGetPackageUid(packageName, packageUserId);
+        mPackageUid = shortcutUser.mService.injectGetPackageUid(packageName, packageUserId);
     }
 
-    public ShortcutPackage(ShortcutService s, ShortcutUser shortcutUser,
-            int packageUserId, String packageName) {
-        this(s, shortcutUser, packageUserId, packageName, null);
+    public ShortcutPackage(ShortcutUser shortcutUser, int packageUserId, String packageName) {
+        this(shortcutUser, packageUserId, packageName, null);
     }
 
     @Override
@@ -122,37 +130,40 @@
     }
 
     /**
-     * Called when a shortcut is about to be published.  At this point we know the publisher package
+     * Called when a shortcut is about to be published.  At this point we know the publisher
+     * package
      * exists (as opposed to Launcher trying to fetch shortcuts from a non-existent package), so
      * we do some initialization for the package.
      */
-    private void onShortcutPublish(ShortcutService s) {
+    private void ensurePackageVersionInfo() {
         // Make sure we have the version code for the app.  We need the version code in
         // handlePackageUpdated().
         if (getPackageInfo().getVersionCode() < 0) {
-            final int versionCode = s.getApplicationVersionCode(getPackageName(), getOwnerUserId());
-            if (ShortcutService.DEBUG) {
-                Slog.d(TAG, String.format("Package %s version = %d", getPackageName(),
-                        versionCode));
-            }
-            if (versionCode >= 0) {
-                getPackageInfo().setVersionCode(versionCode);
+            final ShortcutService s = mShortcutUser.mService;
+
+            final PackageInfo pi = s.getPackageInfo(getPackageName(), getOwnerUserId());
+            if (pi != null) {
+                if (ShortcutService.DEBUG) {
+                    Slog.d(TAG, String.format("Package %s version = %d", getPackageName(),
+                            pi.versionCode));
+                }
+                getPackageInfo().updateVersionInfo(pi);
                 s.scheduleSaveUser(getOwnerUserId());
             }
         }
     }
 
     @Override
-    protected void onRestoreBlocked(ShortcutService s) {
+    protected void onRestoreBlocked() {
         // Can't restore due to version/signature mismatch.  Remove all shortcuts.
         mShortcuts.clear();
     }
 
     @Override
-    protected void onRestored(ShortcutService s) {
+    protected void onRestored() {
         // Because some launchers may not have been restored (e.g. allowBackup=false),
         // we need to re-calculate the pinned shortcuts.
-        refreshPinnedFlags(s);
+        refreshPinnedFlags();
     }
 
     /**
@@ -163,19 +174,43 @@
         return mShortcuts.get(id);
     }
 
-    private ShortcutInfo deleteShortcut(@NonNull ShortcutService s,
-            @NonNull String id) {
+    private void ensureNotImmutable(@Nullable ShortcutInfo shortcut) {
+        if (shortcut != null && shortcut.isImmutable()) {
+            throw new IllegalArgumentException(
+                    "Manifest shortcut ID=" + shortcut.getId()
+                            + " may not be manipulated via APIs");
+        }
+    }
+
+    private void ensureNotImmutable(@NonNull String id) {
+        ensureNotImmutable(mShortcuts.get(id));
+    }
+
+    public void ensureImmutableShortcutsNotIncludedWithIds(@NonNull List<String> shortcutIds) {
+        for (int i = shortcutIds.size() - 1; i >= 0; i--) {
+            ensureNotImmutable(shortcutIds.get(i));
+        }
+    }
+
+    public void ensureImmutableShortcutsNotIncluded(@NonNull List<ShortcutInfo> shortcuts) {
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            ensureNotImmutable(shortcuts.get(i).getId());
+        }
+    }
+
+    private ShortcutInfo deleteShortcutInner(@NonNull String id) {
         final ShortcutInfo shortcut = mShortcuts.remove(id);
         if (shortcut != null) {
-            s.removeIcon(getPackageUserId(), shortcut);
-            shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED);
+            mShortcutUser.mService.removeIcon(getPackageUserId(), shortcut);
+            shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
+                    | ShortcutInfo.FLAG_MANIFEST);
         }
         return shortcut;
     }
 
-    void addShortcut(@NonNull ShortcutService s, @NonNull ShortcutInfo newShortcut) {
-        deleteShortcut(s, newShortcut.getId());
-        s.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut);
+    private void addShortcutInner(@NonNull ShortcutInfo newShortcut) {
+        deleteShortcutInner(newShortcut.getId());
+        mShortcutUser.mService.saveIconAndFixUpShortcut(getPackageUserId(), newShortcut);
         mShortcuts.put(newShortcut.getId(), newShortcut);
     }
 
@@ -184,52 +219,53 @@
      *
      * It checks the max number of dynamic shortcuts.
      */
-    public void addDynamicShortcut(@NonNull ShortcutService s,
-            @NonNull ShortcutInfo newShortcut) {
+    public void addOrUpdateDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
 
-        onShortcutPublish(s);
+        Preconditions.checkArgument(newShortcut.isEnabled(),
+                "add/setDynamicShortcuts() cannot publish disabled shortcuts");
+
+        ensurePackageVersionInfo();
 
         newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
 
         final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
 
         final boolean wasPinned;
-        final int newDynamicCount;
 
         if (oldShortcut == null) {
             wasPinned = false;
-            newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
         } else {
+            // It's an update case.
+            // Make sure the target is updatable. (i.e. should be mutable.)
+            oldShortcut.ensureUpdatableWith(newShortcut);
+
             wasPinned = oldShortcut.isPinned();
-            if (oldShortcut.isDynamic()) {
-                newDynamicCount = mDynamicShortcutCount; // not adding a dynamic shortcut.
-            } else {
-                newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
+            if (!oldShortcut.isEnabled()) {
+                newShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
             }
         }
 
-        // Make sure there's still room.
-        s.enforceMaxDynamicShortcuts(newDynamicCount);
+        // TODO Check max dynamic count.
+        // mShortcutUser.mService.enforceMaxDynamicShortcuts(newDynamicCount);
 
         // Okay, make it dynamic and add.
         if (wasPinned) {
             newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
         }
 
-        addShortcut(s, newShortcut);
-        mDynamicShortcutCount = newDynamicCount;
+        addShortcutInner(newShortcut);
     }
 
     /**
      * Remove all shortcuts that aren't pinned nor dynamic.
      */
-    private void removeOrphans(@NonNull ShortcutService s) {
+    private void removeOrphans() {
         ArrayList<String> removeList = null; // Lazily initialize.
 
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
 
-            if (si.isPinned() || si.isDynamic()) continue;
+            if (si.isAlive()) continue;
 
             if (removeList == null) {
                 removeList = new ArrayList<>();
@@ -238,7 +274,7 @@
         }
         if (removeList != null) {
             for (int i = removeList.size() - 1; i >= 0; i--) {
-                deleteShortcut(s, removeList.get(i));
+                deleteShortcutInner(removeList.get(i));
             }
         }
     }
@@ -246,30 +282,74 @@
     /**
      * Remove all dynamic shortcuts.
      */
-    public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) {
+    public void deleteAllDynamicShortcuts() {
+        boolean changed = false;
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
-            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (si.isDynamic()) {
+                changed = true;
+                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+            }
         }
-        removeOrphans(s);
-        mDynamicShortcutCount = 0;
+        if (changed) {
+            removeOrphans();
+        }
     }
 
     /**
-     * Remove a dynamic shortcut by ID.
+     * Remove a dynamic shortcut by ID.  It'll be removed from the dynamic set, but if the shortcut
+     * is pinned, it'll remain as a pinned shortcut, and is still enabled.
      */
-    public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) {
+    public void deleteDynamicWithId(@NonNull String shortcutId) {
+        deleteOrDisableWithId(shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false);
+    }
+
+    /**
+     * Disable a dynamic shortcut by ID.  It'll be removed from the dynamic set, but if the shortcut
+     * is pinned, it'll remain as a pinned shortcut but will be disabled.
+     */
+    public void disableWithId(@NonNull String shortcutId, String disabledMessage,
+            int disabledMessageResId, boolean overrideImmutable) {
+        final ShortcutInfo disabled = deleteOrDisableWithId(shortcutId, /* disable =*/ true,
+                overrideImmutable);
+
+        if (disabled != null) {
+            if (disabledMessage != null) {
+                disabled.setDisabledMessage(disabledMessage);
+            } else if (disabledMessageResId != 0) {
+                disabled.setDisabledMessageResId(disabledMessageResId);
+            }
+        }
+    }
+
+    @Nullable
+    private ShortcutInfo deleteOrDisableWithId(@NonNull String shortcutId, boolean disable,
+            boolean overrideImmutable) {
         final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
 
-        if (oldShortcut == null) {
-            return;
+        if (oldShortcut == null || !oldShortcut.isEnabled()) {
+            return null; // Doesn't exist or already disabled.
         }
-        if (oldShortcut.isDynamic()) {
-            mDynamicShortcutCount--;
+        if (!overrideImmutable) {
+            ensureNotImmutable(oldShortcut);
         }
         if (oldShortcut.isPinned()) {
-            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
+            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
+            if (disable) {
+                oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
+            }
+            return oldShortcut;
         } else {
-            deleteShortcut(s, shortcutId);
+            deleteShortcutInner(shortcutId);
+            return null;
+        }
+    }
+
+    public void enableWithId(@NonNull String shortcutId) {
+        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
+        if (shortcut != null) {
+            ensureNotImmutable(shortcut);
+            shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
         }
     }
 
@@ -279,14 +359,15 @@
      *
      * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
      */
-    public void refreshPinnedFlags(@NonNull ShortcutService s) {
+    public void refreshPinnedFlags() {
         // First, un-pin all shortcuts
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
         }
 
         // Then, for the pinned set for each launcher, set the pin flag one by one.
-        s.getUserShortcutsLocked(getPackageUserId()).forAllLaunchers(launcherShortcuts -> {
+        mShortcutUser.mService.getUserShortcutsLocked(getPackageUserId())
+                .forAllLaunchers(launcherShortcuts -> {
             final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
                     getPackageName(), getPackageUserId());
 
@@ -308,7 +389,7 @@
         });
 
         // Lastly, remove the ones that are no longer pinned nor dynamic.
-        removeOrphans(s);
+        removeOrphans();
     }
 
     /**
@@ -317,8 +398,10 @@
      * <p>This takes care of the resetting the counter for foreground apps as well as after
      * locale changes.
      */
-    public int getApiCallCount(@NonNull ShortcutService s) {
-        mShortcutUser.resetThrottlingIfNeeded(s);
+    public int getApiCallCount() {
+        mShortcutUser.resetThrottlingIfNeeded();
+
+        final ShortcutService s = mShortcutUser.mService;
 
         // Reset the counter if:
         // - the package is in foreground now.
@@ -328,7 +411,7 @@
                 || mLastKnownForegroundElapsedTime
                     < s.getUidLastForegroundElapsedTimeLocked(mPackageUid)) {
             mLastKnownForegroundElapsedTime = s.injectElapsedRealtime();
-            resetRateLimiting(s);
+            resetRateLimiting();
         }
 
         // Note resetThrottlingIfNeeded() and resetRateLimiting() will set 0 to mApiCallCount,
@@ -349,8 +432,8 @@
         // If not reset yet, then reset.
         if (mLastResetTime < last) {
             if (ShortcutService.DEBUG) {
-                Slog.d(TAG, String.format("My last reset=%d, now=%d, last=%d: resetting",
-                        mLastResetTime, now, last));
+                Slog.d(TAG, String.format("%s: last reset=%d, now=%d, last=%d: resetting",
+                        getPackageName(), mLastResetTime, now, last));
             }
             mApiCallCount = 0;
             mLastResetTime = last;
@@ -365,8 +448,10 @@
      * <p>This takes care of the resetting the counter for foreground apps as well as after
      * locale changes, which is done internally by {@link #getApiCallCount}.
      */
-    public boolean tryApiCall(@NonNull ShortcutService s) {
-        if (getApiCallCount(s) >= s.mMaxUpdatesPerInterval) {
+    public boolean tryApiCall() {
+        final ShortcutService s = mShortcutUser.mService;
+
+        if (getApiCallCount() >= s.mMaxUpdatesPerInterval) {
             return false;
         }
         mApiCallCount++;
@@ -374,13 +459,13 @@
         return true;
     }
 
-    public void resetRateLimiting(@NonNull ShortcutService s) {
+    public void resetRateLimiting() {
         if (ShortcutService.DEBUG) {
             Slog.d(TAG, "resetRateLimiting: " + getPackageName());
         }
         if (mApiCallCount > 0) {
             mApiCallCount = 0;
-            s.scheduleSaveUser(getOwnerUserId());
+            mShortcutUser.mService.scheduleSaveUser(getOwnerUserId());
         }
     }
 
@@ -392,9 +477,9 @@
     /**
      * Find all shortcuts that match {@code query}.
      */
-    public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+    public void findAll(@NonNull List<ShortcutInfo> result,
             @Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
-        findAll(s, result, query, cloneFlag, null, 0);
+        findAll(result, query, cloneFlag, null, 0);
     }
 
     /**
@@ -404,7 +489,7 @@
      * by the calling launcher will not be included in the result, and also "isPinned" will be
      * adjusted for the caller too.
      */
-    public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+    public void findAll(@NonNull List<ShortcutInfo> result,
             @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
             @Nullable String callingLauncher, int launcherUserId) {
         if (getPackageInfo().isShadow()) {
@@ -412,6 +497,8 @@
             return;
         }
 
+        final ShortcutService s = mShortcutUser.mService;
+
         // Set of pinned shortcuts by the calling launcher.
         final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
                 : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
@@ -420,22 +507,19 @@
         for (int i = 0; i < mShortcuts.size(); i++) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
 
-            // If it's called by non-launcher (i.e. publisher, always include -> true.
-            // Otherwise, only include non-dynamic pinned one, if the calling launcher has pinned
-            // it.
+            // Need to adjust PINNED flag depending on the caller.
+            // Basically if the caller is a launcher (callingLauncher != null) and the launcher
+            // isn't pinning it, then we need to clear PINNED for this caller.
             final boolean isPinnedByCaller = (callingLauncher == null)
                     || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
-            if (!si.isDynamic()) {
-                if (!si.isPinned()) {
-                    s.wtf("Shortcut not pinned: package " + getPackageName()
-                            + ", user=" + getPackageUserId() + ", id=" + si.getId());
-                    continue;
-                }
+
+            if (si.isFloating()) {
                 if (!isPinnedByCaller) {
                     continue;
                 }
             }
             final ShortcutInfo clone = si.clone(cloneFlag);
+
             // Fix up isPinned for the caller.  Note we need to do it before the "test" callback,
             // since it may check isPinned.
             if (!isPinnedByCaller) {
@@ -452,30 +536,109 @@
     }
 
     /**
-     * Called when the package is updated.  If there are shortcuts with resource icons, update
-     * their timestamps.
+     * Return the filenames (excluding path names) of icon bitmap files from this package.
      */
-    public void handlePackageUpdated(ShortcutService s, int newVersionCode) {
-        if (getPackageInfo().getVersionCode() >= newVersionCode) {
-            // Version hasn't changed; nothing to do.
-            return;
-        }
-        if (ShortcutService.DEBUG) {
-            Slog.d(TAG, String.format("Package %s updated, version %d -> %d", getPackageName(),
-                    getPackageInfo().getVersionCode(), newVersionCode));
-        }
+    public ArraySet<String> getUsedBitmapFiles() {
+        final ArraySet<String> usedFiles = new ArraySet<>(mShortcuts.size());
 
-        getPackageInfo().setVersionCode(newVersionCode);
-
-        boolean changed = false;
         for (int i = mShortcuts.size() - 1; i >= 0; i--) {
             final ShortcutInfo si = mShortcuts.valueAt(i);
-
-            if (si.hasIconResource()) {
-                changed = true;
-                si.setTimestamp(s.injectCurrentTimeMillis());
+            if (si.getBitmapPath() != null) {
+                usedFiles.add(getFileName(si.getBitmapPath()));
             }
         }
+        return usedFiles;
+    }
+
+    private static String getFileName(@NonNull String path) {
+        final int sep = path.lastIndexOf(File.separatorChar);
+        if (sep == -1) {
+            return path;
+        } else {
+            return path.substring(sep + 1);
+        }
+    }
+
+    /**
+     * Called when the package is updated or added.
+     *
+     * Add case:
+     * - Publish manifest shortcuts.
+     *
+     * Update case:
+     * - Re-publish manifest shortcuts.
+     * - If there are shortcuts with resources (icons or strings), update their timestamps.
+     *
+     * @return TRUE if any shortcuts have been changed.
+     */
+    public boolean handlePackageAddedOrUpdated(boolean isNewApp) {
+        final PackageInfo pi = mShortcutUser.mService.getPackageInfo(
+                getPackageName(), getPackageUserId());
+        if (pi == null) {
+            return false; // Shouldn't happen.
+        }
+
+        if (!isNewApp) {
+            // Make sure the version code or last update time has changed.
+            // Otherwise, nothing to do.
+            if (getPackageInfo().getVersionCode() >= pi.versionCode
+                    && getPackageInfo().getLastUpdateTime() >= pi.lastUpdateTime) {
+                return false;
+            }
+        }
+
+        // Now prepare to publish manifest shortcuts.
+        List<ShortcutInfo> newManifestShortcutList = null;
+        try {
+            newManifestShortcutList = ShortcutParser.parseShortcuts(mShortcutUser.mService,
+                    getPackageName(), getPackageUserId());
+        } catch (IOException|XmlPullParserException e) {
+            Slog.e(TAG, "Failed to load shortcuts from AndroidManifest.xml.", e);
+        }
+        final int manifestShortcutSize = newManifestShortcutList == null ? 0
+                : newManifestShortcutList.size();
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format("Package %s has %d manifest shortcut(s)",
+                    getPackageName(), manifestShortcutSize));
+        }
+        if (isNewApp && (manifestShortcutSize == 0)) {
+            // If it's a new app, and it doesn't have manifest shortcuts, then nothing to do.
+
+            // If it's an update, then it may already have manifest shortcuts, which need to be
+            // disabled.
+            return false;
+        }
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format("Package %s %s, version %d -> %d", getPackageName(),
+                    (isNewApp ? "added" : "updated"),
+                    getPackageInfo().getVersionCode(), pi.versionCode));
+        }
+
+        getPackageInfo().updateVersionInfo(pi);
+
+        final ShortcutService s = mShortcutUser.mService;
+
+        boolean changed = false;
+
+        // For existing shortcuts, update timestamps if they have any resources.
+        if (!isNewApp) {
+            for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+                final ShortcutInfo si = mShortcuts.valueAt(i);
+
+                if (si.hasAnyResources()) {
+                    changed = true;
+                    si.setTimestamp(s.injectCurrentTimeMillis());
+                }
+            }
+        }
+
+        // (Re-)publish manifest shortcut.
+        changed |= publishManifestShortcuts(newManifestShortcutList);
+
+        if (newManifestShortcutList != null) {
+            changed |= pushOutExcessShortcuts();
+        }
+
         if (changed) {
             // This will send a notification to the launcher, and also save .
             s.packageShortcutsChanged(getPackageName(), getPackageUserId());
@@ -483,9 +646,268 @@
             // Still save the version code.
             s.scheduleSaveUser(getPackageUserId());
         }
+        return changed;
     }
 
-    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+    private boolean publishManifestShortcuts(List<ShortcutInfo> newManifestShortcutList) {
+        if (ShortcutService.DEBUG) {
+            Slog.d(TAG, String.format(
+                    "Package %s: publishing manifest shortcuts", getPackageName()));
+        }
+        boolean changed = false;
+
+        // Keep the previous IDs.
+        ArraySet<String> toDisableList = null;
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+
+            if (si.isManifestShortcut()) {
+                if (toDisableList == null) {
+                    toDisableList = new ArraySet<>();
+                }
+                toDisableList.add(si.getId());
+            }
+        }
+
+        // Publish new ones.
+        if (newManifestShortcutList != null) {
+            final int newListSize = newManifestShortcutList.size();
+
+            for (int i = 0; i < newListSize; i++) {
+                changed = true;
+
+                final ShortcutInfo newShortcut = newManifestShortcutList.get(i);
+                final boolean newDisabled = !newShortcut.isEnabled();
+
+                final String id = newShortcut.getId();
+                final ShortcutInfo oldShortcut = mShortcuts.get(id);
+
+                boolean wasPinned = false;
+
+                if (oldShortcut != null) {
+                    if (!oldShortcut.isOriginallyFromManifest()) {
+                        Slog.e(TAG, "Shortcut with ID=" + newShortcut.getId()
+                                + " exists but is not from AndroidManifest.xml, not updating.");
+                        continue;
+                    }
+                    // Take over the pinned flag.
+                    if (oldShortcut.isPinned()) {
+                        wasPinned = true;
+                        newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+                    }
+                }
+                if (newDisabled && !wasPinned) {
+                    // If the shortcut is disabled, and it was *not* pinned, then this
+                    // just doesn't have to be published.
+                    // Just keep it in toDisableList, so the previous one would be removed.
+                    continue;
+                }
+
+                // Note even if enabled=false, we still need to update all fields, so do it
+                // regardless.
+                addShortcutInner(newShortcut); // This will clean up the old one too.
+
+                if (!newDisabled && toDisableList != null) {
+                    // Still alive, don't remove.
+                    toDisableList.remove(id);
+                }
+            }
+        }
+
+        // Disable the previous manifest shortcuts that are no longer in the manifest.
+        if (toDisableList != null) {
+            if (ShortcutService.DEBUG) {
+                Slog.d(TAG, String.format(
+                        "Package %s: disabling %d stale shortcuts", getPackageName(),
+                        toDisableList.size()));
+            }
+            for (int i = toDisableList.size() - 1; i >= 0; i--) {
+                changed = true;
+
+                final String id = toDisableList.valueAt(i);
+
+                disableWithId(id, /* disable message =*/ null, /* disable message resid */ 0,
+                        /* overrideImmutable=*/ true);
+            }
+            removeOrphans();
+        }
+        return changed;
+    }
+
+    /**
+     * For each target activity, make sure # of dynamic + manifest shortcuts <= max.
+     * If too many, we'll remove the dynamic with the lowest ranks.
+     */
+    private boolean pushOutExcessShortcuts() {
+        final ShortcutService service = mShortcutUser.mService;
+        final int maxShortcuts = service.getMaxActivityShortcuts();
+
+        boolean changed = false;
+
+        final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
+                sortShortcutsToActivities();
+        for (int outer = all.size() - 1; outer >= 0; outer--) {
+            final ArrayList<ShortcutInfo> list = all.valueAt(outer);
+            if (list.size() <= maxShortcuts) {
+                continue;
+            }
+            // Sort by isManifestShortcut() and getRank().
+            Collections.sort(list, mShortcutTypeAndRankComparator);
+
+            // Keep [0 .. max), and remove (as dynamic) [max .. size)
+            for (int inner = list.size() - 1; inner >= maxShortcuts; inner--) {
+                final ShortcutInfo shortcut = list.get(inner);
+
+                if (shortcut.isManifestShortcut()) {
+                    // This shouldn't happen -- excess shortcuts should all be non-manifest.
+                    // But just in case.
+                    service.wtf("Found manifest shortcuts in excess list.");
+                    continue;
+                }
+                deleteDynamicWithId(shortcut.getId());
+            }
+        }
+        service.verifyStates();
+
+        return changed;
+    }
+
+    /**
+     * To sort by isManifestShortcut() and getRank(). i.e.  manifest shortcuts come before
+     * non-manifest shortcuts, then sort by rank.
+     *
+     * This is used to decide which dynamic shortcuts to remove when an upgraded version has more
+     * manifest shortcuts than before and as a result we need to remove some of the dynamic
+     * shortcuts.  We sort manifest + dynamic shortcuts by this order, and remove the ones with
+     * the last ones.
+     *
+     * (Note the number of manifest shortcuts is always <= the max number, because if there are
+     * more, ShortcutParser would ignore the rest.)
+     */
+    final Comparator<ShortcutInfo> mShortcutTypeAndRankComparator = (ShortcutInfo a,
+            ShortcutInfo b) -> {
+        if (a.isManifestShortcut() && !b.isManifestShortcut()) {
+            return -1;
+        }
+        if (!a.isManifestShortcut() && b.isManifestShortcut()) {
+            return 1;
+        }
+        return a.getRank() - b.getRank();
+    };
+
+    /**
+     * Build a list of shortcuts for each target activity and return as a map. The result won't
+     * contain "floating" shortcuts because they don't belong on any activities.
+     */
+    private ArrayMap<ComponentName, ArrayList<ShortcutInfo>> sortShortcutsToActivities() {
+        final int maxShortcuts = mShortcutUser.mService.getMaxActivityShortcuts();
+
+        final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> activitiesToShortcuts
+                = new ArrayMap<>();
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (si.isFloating()) {
+                continue; // Ignore floating shortcuts, which are not tied to any activities.
+            }
+
+            final ComponentName activity = si.getActivity();
+
+            ArrayList<ShortcutInfo> list = activitiesToShortcuts.get(activity);
+            if (list == null) {
+                list = new ArrayList<>(maxShortcuts * 2);
+                activitiesToShortcuts.put(activity, list);
+            }
+            list.add(si);
+        }
+        return activitiesToShortcuts;
+    }
+
+    /** Used by {@link #enforceShortcutCountsBeforeOperation} */
+    private void incrementCountForActivity(ArrayMap<ComponentName, Integer> counts,
+            ComponentName cn, int increment) {
+        Integer oldValue = counts.get(cn);
+        if (oldValue == null) {
+            oldValue = 0;
+        }
+
+        counts.put(cn, oldValue + increment);
+    }
+
+    /**
+     * Called by
+     * {@link android.content.pm.ShortcutManager#setDynamicShortcuts},
+     * {@link android.content.pm.ShortcutManager#addDynamicShortcuts}, and
+     * {@link android.content.pm.ShortcutManager#updateShortcuts} before actually performing
+     * the operation to make sure the operation wouldn't result in the target activities having
+     * more than the allowed number of dynamic/manifest shortcuts.
+     *
+     * @param newList shortcut list passed to set, add or updateShortcuts().
+     * @param operation add, set or update.
+     * @throws IllegalArgumentException if the operation would result in going over the max
+     *                                  shortcut count for any activity.
+     */
+    public void enforceShortcutCountsBeforeOperation(List<ShortcutInfo> newList,
+            @ShortcutOperation int operation) {
+        final ShortcutService service = mShortcutUser.mService;
+
+        // Current # of dynamic / manifest shortcuts for each activity.
+        // (If it's for update, then don't count dynamic shortcuts, since they'll be replaced
+        // anyway.)
+        final ArrayMap<ComponentName, Integer> counts = new ArrayMap<>(4);
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo shortcut = mShortcuts.valueAt(i);
+
+            if (shortcut.isManifestShortcut()) {
+                incrementCountForActivity(counts, shortcut.getActivity(), 1);
+            } else if (shortcut.isDynamic() && (operation != ShortcutService.OPERATION_SET)) {
+                incrementCountForActivity(counts, shortcut.getActivity(), 1);
+            }
+        }
+
+        for (int i = newList.size() - 1; i >= 0; i--) {
+            final ShortcutInfo newShortcut = newList.get(i);
+            final ComponentName newActivity = newShortcut.getActivity();
+            if (newActivity == null) {
+                if (operation != ShortcutService.OPERATION_UPDATE) {
+                    service.wtf("null Activity found for non-update");
+                }
+                continue; // Activity can be null for update.
+            }
+
+            final ShortcutInfo original = mShortcuts.get(newShortcut.getId());
+            if (original == null) {
+                if (operation == ShortcutService.OPERATION_UPDATE) {
+                    continue; // When updating, ignore if there's no target.
+                }
+                // Add() or set(), and there's no existing shortcut with the same ID.  We're
+                // simply publishing (as opposed to updating) this shortcut, so just +1.
+                incrementCountForActivity(counts, newActivity, 1);
+                continue;
+            }
+            if (original.isFloating() && (operation == ShortcutService.OPERATION_UPDATE)) {
+                // Updating floating shortcuts doesn't affect the count, so ignore.
+                continue;
+            }
+
+            // If it's add() or update(), then need to decrement for the previous activity.
+            // Skip it for set() since it's already been taken care of by not counting the original
+            // dynamic shortcuts in the first loop.
+            if (operation != ShortcutService.OPERATION_SET) {
+                final ComponentName oldActivity = original.getActivity();
+                if (!original.isFloating()) {
+                    incrementCountForActivity(counts, oldActivity, -1);
+                }
+            }
+            incrementCountForActivity(counts, newActivity, 1);
+        }
+
+        // Then make sure none of the activities have more than the max number of shortcuts.
+        for (int i = counts.size() - 1; i >= 0; i--) {
+            service.enforceMaxActivityShortcuts(counts.valueAt(i));
+        }
+    }
+
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.println();
 
         pw.print(prefix);
@@ -498,7 +920,7 @@
         pw.print(prefix);
         pw.print("  ");
         pw.print("Calls: ");
-        pw.print(getApiCallCount(s));
+        pw.print(getApiCallCount());
         pw.println();
 
         // getApiCallCount() may have updated mLastKnownForegroundElapsedTime.
@@ -514,10 +936,10 @@
         pw.print("Last reset: [");
         pw.print(mLastResetTime);
         pw.print("] ");
-        pw.print(s.formatTime(mLastResetTime));
+        pw.print(ShortcutService.formatTime(mLastResetTime));
         pw.println();
 
-        getPackageInfo().dump(s, pw, prefix + "  ");
+        getPackageInfo().dump(pw, prefix + "  ");
         pw.println();
 
         pw.print(prefix);
@@ -545,7 +967,7 @@
         pw.print("Total bitmap size: ");
         pw.print(totalBitmapSize);
         pw.print(" (");
-        pw.print(Formatter.formatFileSize(s.mContext, totalBitmapSize));
+        pw.print(Formatter.formatFileSize(mShortcutUser.mService.mContext, totalBitmapSize));
         pw.println(")");
     }
 
@@ -561,7 +983,6 @@
         out.startTag(null, TAG_ROOT);
 
         ShortcutService.writeAttr(out, ATTR_NAME, getPackageName());
-        ShortcutService.writeAttr(out, ATTR_DYNAMIC_COUNT, mDynamicShortcutCount);
         ShortcutService.writeAttr(out, ATTR_CALL_COUNT, mApiCallCount);
         ShortcutService.writeAttr(out, ATTR_LAST_RESET, mLastResetTime);
         getPackageInfo().saveToXml(out);
@@ -583,12 +1004,17 @@
         out.startTag(null, TAG_SHORTCUT);
         ShortcutService.writeAttr(out, ATTR_ID, si.getId());
         // writeAttr(out, "package", si.getPackageName()); // not needed
-        ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivityComponent());
+        ShortcutService.writeAttr(out, ATTR_ACTIVITY, si.getActivity());
         // writeAttr(out, "icon", si.getIcon());  // We don't save it.
         ShortcutService.writeAttr(out, ATTR_TITLE, si.getTitle());
+        ShortcutService.writeAttr(out, ATTR_TITLE_RES_ID, si.getTitleResId());
         ShortcutService.writeAttr(out, ATTR_TEXT, si.getText());
+        ShortcutService.writeAttr(out, ATTR_TEXT_RES_ID, si.getTextResId());
+        ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE, si.getDisabledMessage());
+        ShortcutService.writeAttr(out, ATTR_DISABLED_MESSAGE_RES_ID,
+                si.getDisabledMessageResourceId());
         ShortcutService.writeAttr(out, ATTR_INTENT, si.getIntentNoExtras());
-        ShortcutService.writeAttr(out, ATTR_WEIGHT, si.getWeight());
+        ShortcutService.writeAttr(out, ATTR_RANK, si.getRank());
         ShortcutService.writeAttr(out, ATTR_TIMESTAMP,
                 si.getLastChangedTimestamp());
         if (forBackup) {
@@ -627,11 +1053,9 @@
         final String packageName = ShortcutService.parseStringAttribute(parser,
                 ATTR_NAME);
 
-        final ShortcutPackage ret = new ShortcutPackage(s, shortcutUser,
+        final ShortcutPackage ret = new ShortcutPackage(shortcutUser,
                 shortcutUser.getUserId(), packageName);
 
-        ret.mDynamicShortcutCount =
-                ShortcutService.parseIntAttribute(parser, ATTR_DYNAMIC_COUNT);
         ret.mApiCallCount =
                 ShortcutService.parseIntAttribute(parser, ATTR_CALL_COUNT);
         ret.mLastResetTime =
@@ -671,10 +1095,14 @@
         ComponentName activityComponent;
         // Icon icon;
         String title;
+        int titleResId;
         String text;
+        int textResId;
+        String disabledMessage;
+        int disabledMessageResId;
         Intent intent;
         PersistableBundle intentPersistableExtras = null;
-        int weight;
+        int rank;
         PersistableBundle extras = null;
         long lastChangedTimestamp;
         int flags;
@@ -686,9 +1114,14 @@
         activityComponent = ShortcutService.parseComponentNameAttribute(parser,
                 ATTR_ACTIVITY);
         title = ShortcutService.parseStringAttribute(parser, ATTR_TITLE);
+        titleResId = ShortcutService.parseIntAttribute(parser, ATTR_TITLE_RES_ID);
         text = ShortcutService.parseStringAttribute(parser, ATTR_TEXT);
+        textResId = ShortcutService.parseIntAttribute(parser, ATTR_TEXT_RES_ID);
+        disabledMessage = ShortcutService.parseStringAttribute(parser, ATTR_DISABLED_MESSAGE);
+        disabledMessageResId = ShortcutService.parseIntAttribute(parser,
+                ATTR_DISABLED_MESSAGE_RES_ID);
         intent = ShortcutService.parseIntentAttribute(parser, ATTR_INTENT);
-        weight = (int) ShortcutService.parseLongAttribute(parser, ATTR_WEIGHT);
+        rank = (int) ShortcutService.parseLongAttribute(parser, ATTR_RANK);
         lastChangedTimestamp = ShortcutService.parseLongAttribute(parser, ATTR_TIMESTAMP);
         flags = (int) ShortcutService.parseLongAttribute(parser, ATTR_FLAGS);
         iconRes = (int) ShortcutService.parseLongAttribute(parser, ATTR_ICON_RES);
@@ -733,9 +1166,10 @@
         }
 
         return new ShortcutInfo(
-                userId, id, packageName, activityComponent, /* icon =*/ null, title, text,
+                userId, id, packageName, activityComponent, /* icon =*/ null,
+                title, titleResId, text, textResId, disabledMessage, disabledMessageResId,
                 categories, intent,
-                intentPersistableExtras, weight, extras, lastChangedTimestamp, flags,
+                intentPersistableExtras, rank, extras, lastChangedTimestamp, flags,
                 iconRes, bitmapPath);
     }
 
@@ -743,4 +1177,46 @@
     List<ShortcutInfo> getAllShortcutsForTest() {
         return new ArrayList<>(mShortcuts.values());
     }
+
+    @Override
+    public void verifyStates() {
+        super.verifyStates();
+
+        boolean failed = false;
+
+        final ArrayMap<ComponentName, ArrayList<ShortcutInfo>> all =
+                sortShortcutsToActivities();
+
+        // Make sure each activity won't have more than max shortcuts.
+        for (int i = all.size() - 1; i >= 0; i--) {
+            if (all.valueAt(i).size() > mShortcutUser.mService.getMaxActivityShortcuts()) {
+                failed = true;
+                Log.e(TAG, "Package " + getPackageName() + ": activity " + all.keyAt(i)
+                        + " has " + all.valueAt(i).size() + " shortcuts.");
+            }
+        }
+
+        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
+            final ShortcutInfo si = mShortcuts.valueAt(i);
+            if (!(si.isManifestShortcut() || si.isDynamic() || si.isPinned())) {
+                failed = true;
+                Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " is not manifest, dynamic or pinned.");
+            }
+            if (si.getActivity() == null) {
+                failed = true;
+                Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " has null activity.");
+            }
+            if ((si.isDynamic() || si.isManifestShortcut()) && !si.isEnabled()) {
+                failed = true;
+                Log.e(TAG, "Package " + getPackageName() + ": shortcut " + si.getId()
+                        + " is not floating, but is disabled.");
+            }
+        }
+
+        if (failed) {
+            throw new IllegalStateException("See logcat for errors");
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 74969f0..7f5d931 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageInfo;
 import android.util.Slog;
@@ -34,12 +35,15 @@
 
 /**
  * Package information used by {@link android.content.pm.ShortcutManager} for backup / restore.
+ *
+ * All methods should be guarded by {@code ShortcutService.mLock}.
  */
 class ShortcutPackageInfo {
     private static final String TAG = ShortcutService.TAG;
 
     static final String TAG_ROOT = "package-info";
     private static final String ATTR_VERSION = "version";
+    private static final String ATTR_LAST_UPDATE_TIME = "last_udpate_time";
     private static final String ATTR_SHADOW = "shadow";
 
     private static final String TAG_SIGNATURE = "signature";
@@ -53,16 +57,20 @@
      */
     private boolean mIsShadow;
     private int mVersionCode = VERSION_UNKNOWN;
+    private long mLastUpdateTime;
     private ArrayList<byte[]> mSigHashes;
 
-    private ShortcutPackageInfo(int versionCode, ArrayList<byte[]> sigHashes, boolean isShadow) {
+    private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
+            ArrayList<byte[]> sigHashes, boolean isShadow) {
         mVersionCode = versionCode;
+        mLastUpdateTime = lastUpdateTime;
         mIsShadow = isShadow;
         mSigHashes = sigHashes;
     }
 
     public static ShortcutPackageInfo newEmpty() {
-        return new ShortcutPackageInfo(VERSION_UNKNOWN, new ArrayList<>(0), /* isShadow */ false);
+        return new ShortcutPackageInfo(VERSION_UNKNOWN, /* last update time =*/ 0,
+                new ArrayList<>(0), /* isShadow */ false);
     }
 
     public boolean isShadow() {
@@ -77,8 +85,15 @@
         return mVersionCode;
     }
 
-    public void setVersionCode(int versionCode) {
-        mVersionCode = versionCode;
+    public long getLastUpdateTime() {
+        return mLastUpdateTime;
+    }
+
+    public void updateVersionInfo(@NonNull PackageInfo pi) {
+        if (pi != null) {
+            mVersionCode = pi.versionCode;
+            mLastUpdateTime = pi.lastUpdateTime;
+        }
     }
 
     public boolean hasSignatures() {
@@ -111,7 +126,7 @@
             Slog.e(TAG, "Can't get signatures: package=" + packageName);
             return null;
         }
-        final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode,
+        final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
                 BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
 
         return ret;
@@ -131,6 +146,7 @@
             return;
         }
         mVersionCode = pi.versionCode;
+        mLastUpdateTime = pi.lastUpdateTime;
         mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
     }
 
@@ -139,6 +155,7 @@
         out.startTag(null, TAG_ROOT);
 
         ShortcutService.writeAttr(out, ATTR_VERSION, mVersionCode);
+        ShortcutService.writeAttr(out, ATTR_LAST_UPDATE_TIME, mLastUpdateTime);
         ShortcutService.writeAttr(out, ATTR_SHADOW, mIsShadow);
 
         for (int i = 0; i < mSigHashes.size(); i++) {
@@ -154,6 +171,9 @@
 
         final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION);
 
+        final long lastUpdateTime = ShortcutService.parseIntAttribute(
+                parser, ATTR_LAST_UPDATE_TIME);
+
         // When restoring from backup, it's always shadow.
         final boolean shadow =
                 fromBackup || ShortcutService.parseBooleanAttribute(parser, ATTR_SHADOW);
@@ -185,11 +205,12 @@
 
         // Successfully loaded; replace the feilds.
         mVersionCode = versionCode;
+        mLastUpdateTime = lastUpdateTime;
         mIsShadow = shadow;
         mSigHashes = hashes;
     }
 
-    public void dump(ShortcutService s, PrintWriter pw, String prefix) {
+    public void dump(PrintWriter pw, String prefix) {
         pw.println();
 
         pw.print(prefix);
@@ -205,6 +226,11 @@
         pw.print(mVersionCode);
         pw.println();
 
+        pw.print(prefix);
+        pw.print("  Last package update time: ");
+        pw.print(mLastUpdateTime);
+        pw.println();
+
         for (int i = 0; i < mSigHashes.size(); i++) {
             pw.print(prefix);
             pw.print("    ");
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 6fbdb82..757dd19 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -26,6 +26,9 @@
 
 import java.io.IOException;
 
+/**
+ * All methods should be guarded by {@code #mShortcutUser.mService.mLock}.
+ */
 abstract class ShortcutPackageItem {
     private static final String TAG = ShortcutService.TAG;
 
@@ -69,18 +72,20 @@
         return mPackageInfo;
     }
 
-    public void refreshPackageInfoAndSave(ShortcutService s) {
+    public void refreshPackageInfoAndSave() {
         if (mPackageInfo.isShadow()) {
             return; // Don't refresh for shadow user.
         }
+        final ShortcutService s = mShortcutUser.mService;
         mPackageInfo.refresh(s, this);
         s.scheduleSaveUser(getOwnerUserId());
     }
 
-    public void attemptToRestoreIfNeededAndSave(ShortcutService s) {
+    public void attemptToRestoreIfNeededAndSave() {
         if (!mPackageInfo.isShadow()) {
             return; // Already installed, nothing to do.
         }
+        final ShortcutService s = mShortcutUser.mService;
         if (!s.isPackageInstalled(mPackageName, mPackageUserId)) {
             if (ShortcutService.DEBUG) {
                 Slog.d(TAG, String.format("Package still not installed: %s user=%d",
@@ -91,14 +96,14 @@
         if (!mPackageInfo.hasSignatures()) {
             s.wtf("Attempted to restore package " + mPackageName + ", user=" + mPackageUserId
                     + " but signatures not found in the restore data.");
-            onRestoreBlocked(s);
+            onRestoreBlocked();
             return;
         }
 
         final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
         if (!mPackageInfo.canRestoreTo(s, pi)) {
             // Package is now installed, but can't restore.  Let the subclass do the cleanup.
-            onRestoreBlocked(s);
+            onRestoreBlocked();
             return;
         }
         if (ShortcutService.DEBUG) {
@@ -106,7 +111,7 @@
                     mPackageUserId, getOwnerUserId()));
         }
 
-        onRestored(s);
+        onRestored();
 
         // Now the package is not shadow.
         mPackageInfo.setShadow(false);
@@ -118,13 +123,19 @@
      * Called when the new package can't be restored because it has a lower version number
      * or different signatures.
      */
-    protected abstract void onRestoreBlocked(ShortcutService s);
+    protected abstract void onRestoreBlocked();
 
     /**
      * Called when the new package is successfully restored.
      */
-    protected abstract void onRestored(ShortcutService s);
+    protected abstract void onRestored();
 
     public abstract void saveToXml(@NonNull XmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException;
+
+    /**
+     * Verify various internal states.
+     */
+    public void verifyStates() {
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutParser.java b/services/core/java/com/android/server/pm/ShortcutParser.java
new file mode 100644
index 0000000..3eda13e
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ShortcutParser.java
@@ -0,0 +1,246 @@
+/*
+ * 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.pm;
+
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.ShortcutInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class ShortcutParser {
+    private static final String TAG = ShortcutService.TAG;
+
+    private static final boolean DEBUG = ShortcutService.DEBUG || false; // DO NOT SUBMIT WITH TRUE
+
+    @VisibleForTesting
+    static final String METADATA_KEY = "android.pm.Shortcuts";
+
+    private static final String TAG_SHORTCUTS = "shortcuts";
+    private static final String TAG_SHORTCUT = "shortcut";
+
+    @Nullable
+    public static List<ShortcutInfo> parseShortcuts(ShortcutService service,
+            String packageName, @UserIdInt int userId) throws IOException, XmlPullParserException {
+        final PackageInfo pi = service.injectGetActivitiesWithMetadata(packageName, userId);
+
+        List<ShortcutInfo> result = null;
+
+        if (pi != null && pi.activities != null) {
+            for (ActivityInfo activityInfo : pi.activities) {
+                result = parseShortcutsOneFile(service, activityInfo, packageName, userId, result);
+            }
+        }
+        return result;
+    }
+
+    private static List<ShortcutInfo> parseShortcutsOneFile(
+            ShortcutService service,
+            ActivityInfo activityInfo, String packageName, @UserIdInt int userId,
+            List<ShortcutInfo> result) throws IOException, XmlPullParserException {
+        XmlResourceParser parser = null;
+        try {
+            parser = service.injectXmlMetaData(activityInfo, METADATA_KEY);
+            if (parser == null) {
+                return result;
+            }
+
+            final ComponentName activity = new ComponentName(packageName, activityInfo.name);
+
+            final AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+
+            int rank = 0;
+            final int maxShortcuts = service.getMaxActivityShortcuts();
+            int numShortcuts = 0;
+
+            outer:
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > 0)) {
+                if (type != XmlPullParser.START_TAG) {
+                    continue;
+                }
+                final int depth = parser.getDepth();
+                final String tag = parser.getName();
+
+                if (depth == 1 && TAG_SHORTCUTS.equals(tag)) {
+                    continue; // Root tag.
+                }
+                if (depth == 2 && TAG_SHORTCUT.equals(tag)) {
+                    final ShortcutInfo si = parseShortcutAttributes(
+                            service, attrs, packageName, activity, userId, rank++);
+                    if (ShortcutService.DEBUG) {
+                        Slog.d(TAG, "Shortcut=" + si);
+                    }
+                    if (result != null) {
+                        for (int i = result.size() - 1; i >= 0; i--) {
+                            if (si.getId().equals(result.get(i).getId())) {
+                                Slog.w(TAG, "Duplicate shortcut ID detected, skipping.");
+                                continue outer;
+                            }
+                        }
+                    }
+
+                    if (si != null) {
+                        if (numShortcuts >= maxShortcuts) {
+                            Slog.w(TAG, "More than " + maxShortcuts + " shortcuts found for "
+                                    + activityInfo.getComponentName() + ", ignoring the rest.");
+                            return result;
+                        }
+
+                        if (result == null) {
+                            result = new ArrayList<>();
+                        }
+                        result.add(si);
+                        numShortcuts++;
+                    }
+                    continue;
+                }
+                Slog.w(TAG, "Unknown tag " + tag);
+            }
+        } finally {
+            if (parser != null) {
+                parser.close();
+            }
+        }
+        return result;
+    }
+
+    private static ShortcutInfo parseShortcutAttributes(ShortcutService service,
+            AttributeSet attrs, String packageName, ComponentName activity,
+            @UserIdInt int userId, int rank) {
+        final TypedArray sa = service.mContext.getResources().obtainAttributes(attrs,
+                R.styleable.Shortcut);
+        try {
+            final String id = sa.getString(R.styleable.Shortcut_shortcutId);
+            final boolean enabled = sa.getBoolean(R.styleable.Shortcut_enabled, true);
+            final int iconResId = sa.getResourceId(R.styleable.Shortcut_shortcutIcon, 0);
+            final int titleResId = sa.getResourceId(R.styleable.Shortcut_shortcutShortLabel, 0);
+            final int textResId = sa.getResourceId(R.styleable.Shortcut_shortcutLongLabel, 0);
+            final int disabledMessageResId = sa.getResourceId(
+                    R.styleable.Shortcut_shortcutDisabledMessage, 0);
+            final String categories = sa.getString(R.styleable.Shortcut_shortcutCategories);
+            String intentAction = sa.getString(R.styleable.Shortcut_shortcutIntentAction);
+            final String intentData = sa.getString(R.styleable.Shortcut_shortcutIntentData);
+
+            if (TextUtils.isEmpty(id)) {
+                Slog.w(TAG, "Shortcut ID must be provided. activity=" + activity);
+                return null;
+            }
+            if (titleResId == 0) {
+                Slog.w(TAG, "Shortcut title must be provided. activity=" + activity);
+                return null;
+            }
+            if (TextUtils.isEmpty(intentAction)) {
+                if (enabled) {
+                    Slog.w(TAG, "Shortcut intent action must be provided. activity=" + activity);
+                    return null;
+                } else {
+                    // Disabled shortcut doesn't have to have an action, but just set VIEW as the
+                    // default.
+                    intentAction = Intent.ACTION_VIEW;
+                }
+            }
+
+            final ArraySet<String> categoriesSet;
+            if (categories == null) {
+                categoriesSet = null;
+            } else {
+                final String[] arr = categories.split(":");
+                categoriesSet = new ArraySet<>(arr.length);
+                for (String v : arr) {
+                    categoriesSet.add(v);
+                }
+            }
+            final Intent intent = new Intent(intentAction);
+            if (!TextUtils.isEmpty(intentData)) {
+                intent.setData(Uri.parse(intentData));
+            }
+
+            return createShortcutFromManifest(
+                    service,
+                    userId,
+                    id,
+                    packageName,
+                    activity,
+                    titleResId,
+                    textResId,
+                    disabledMessageResId,
+                    categoriesSet,
+                    intent,
+                    rank,
+                    iconResId,
+                    enabled);
+        } finally {
+            sa.recycle();
+        }
+    }
+
+    private static ShortcutInfo createShortcutFromManifest(ShortcutService service,
+            @UserIdInt int userId, String id, String packageName, ComponentName activityComponent,
+            int titleResId, int textResId, int disabledMessageResId, Set<String> categories,
+            Intent intent, int rank, int iconResId, boolean enabled) {
+
+        final int flags =
+                (enabled ? ShortcutInfo.FLAG_MANIFEST : ShortcutInfo.FLAG_DISABLED)
+                | ShortcutInfo.FLAG_IMMUTABLE
+                | ((iconResId != 0) ? ShortcutInfo.FLAG_HAS_ICON_RES : 0);
+
+        return new ShortcutInfo(
+                userId,
+                id,
+                packageName,
+                activityComponent,
+                null, // icon
+                null, // title string
+                titleResId,
+                null, // text string
+                textResId,
+                null, // disabled message string
+                disabledMessageResId,
+                categories,
+                intent,
+                null, // intent extras
+                rank,
+                null, // extras
+                service.injectCurrentTimeMillis(),
+                flags,
+                iconResId,
+                null); // bitmap path
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 8268776..7835231 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.pm;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -22,9 +23,11 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.IUidObserver;
+import android.app.usage.UsageStatsManagerInternal;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.IShortcutService;
@@ -32,12 +35,14 @@
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ShortcutInfo;
 import android.content.pm.ShortcutServiceInternal;
 import android.content.pm.ShortcutServiceInternal.ShortcutChangeListener;
+import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.Canvas;
@@ -63,6 +68,7 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.KeyValueListParser;
+import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseIntArray;
@@ -74,7 +80,6 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
@@ -100,33 +105,46 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.URISyntaxException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
  * TODO:
+ * - HandleUnlockUser needs to be async.  Wait on it in onCleanupUser.
+ *
+ * - Implement reportShortcutUsed().
+ *
+ * - validateForXml() should be removed.
+ *
+ * - Ranks should be recalculated after each update.
+ *
+ * - When the system locale changes, update timestamps for shortcuts with string resources,
+ *   and notify the launcher.  Right now, it resets the throttling, but timestamps are not changed
+ *   and there's no notification either.
+ *
+ * - getIconMaxWidth()/getIconMaxHeight() should use xdpi and ydpi.
  *
  * - Default launcher check does take a few ms.  Worth caching.
  *
- * - Clear data -> remove all dynamic?  but not the pinned?
- *
- * - Scan and remove orphan bitmaps (just in case).
- *
  * - Detect when already registered instances are passed to APIs again, which might break
  *   internal bitmap handling.
  *
  * - Add more call stats.
+ *
+ * - Rename mMaxDynamicShortcuts, because it includes manifest shortcuts too.
  */
 public class ShortcutService extends IShortcutService.Stub {
     static final String TAG = "ShortcutService";
 
-    public static final boolean FEATURE_ENABLED = false;
-
     static final boolean DEBUG = false; // STOPSHIP if true
     static final boolean DEBUG_LOAD = false; // STOPSHIP if true
     static final boolean DEBUG_PROCSTATE = false; // STOPSHIP if true
@@ -261,6 +279,7 @@
     private final IPackageManager mIPackageManager;
     private final PackageManagerInternal mPackageManagerInternal;
     private final UserManager mUserManager;
+    private final UsageStatsManagerInternal mUsageStatsManagerInternal;
 
     @GuardedBy("mLock")
     final SparseIntArray mUidState = new SparseIntArray();
@@ -280,6 +299,8 @@
      */
     private final AtomicLong mLocaleChangeSequenceNumber = new AtomicLong();
 
+    private final AtomicBoolean mBootCompleted = new AtomicBoolean();
+
     private static final int PACKAGE_MATCH_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE
             | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
@@ -293,8 +314,12 @@
         int GET_PACKAGE_INFO_WITH_SIG = 2;
         int GET_APPLICATION_INFO = 3;
         int LAUNCHER_PERMISSION_CHECK = 4;
+        int CLEANUP_DANGLING_BITMAPS = 5;
+        int GET_ACTIVITIES_WITH_METADATA = 6;
+        int GET_INSTALLED_APPLICATIONS = 7;
+        int CHECK_PACKAGE_CHANGES = 8;
 
-        int COUNT = LAUNCHER_PERMISSION_CHECK + 1;
+        int COUNT = CHECK_PACKAGE_CHANGES + 1;
     }
 
     final Object mStatLock = new Object();
@@ -308,6 +333,19 @@
     private static final int PROCESS_STATE_FOREGROUND_THRESHOLD =
             ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
 
+    static final int OPERATION_SET = 0;
+    static final int OPERATION_ADD = 1;
+    static final int OPERATION_UPDATE = 2;
+
+    /** @hide */
+    @IntDef(value = {
+            OPERATION_SET,
+            OPERATION_ADD,
+            OPERATION_UPDATE
+            })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ShortcutOperation {}
+
     public ShortcutService(Context context) {
         this(context, BackgroundThread.get().getLooper());
     }
@@ -318,12 +356,12 @@
         LocalServices.addService(ShortcutServiceInternal.class, new LocalService());
         mHandler = new Handler(looper);
         mIPackageManager = AppGlobals.getPackageManager();
-        mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
-        mUserManager = context.getSystemService(UserManager.class);
+        mPackageManagerInternal = Preconditions.checkNotNull(
+                LocalServices.getService(PackageManagerInternal.class));
+        mUserManager = Preconditions.checkNotNull(context.getSystemService(UserManager.class));
+        mUsageStatsManagerInternal = Preconditions.checkNotNull(
+                LocalServices.getService(UsageStatsManagerInternal.class));
 
-        if (!FEATURE_ENABLED) {
-            return;
-        }
         mPackageMonitor.register(context, looper, UserHandle.ALL, /* externalStorage= */ false);
 
         injectRegisterUidObserver(mUidObserver, ActivityManager.UID_OBSERVER_PROCSTATE
@@ -333,7 +371,7 @@
     void logDurationStat(int statId, long start) {
         synchronized (mStatLock) {
             mCountStats[statId]++;
-            mDurationStats[statId] += (System.currentTimeMillis() - start);
+            mDurationStats[statId] += (injectElapsedRealtime() - start);
         }
     }
 
@@ -424,7 +462,6 @@
 
     /** lifecycle event */
     void onBootPhase(int phase) {
-        // We want to call initialize() to initialize the configurations, so we don't disable this.
         if (DEBUG) {
             Slog.d(TAG, "onBootPhase: " + phase);
         }
@@ -432,13 +469,16 @@
             case SystemService.PHASE_LOCK_SETTINGS_READY:
                 initialize();
                 break;
+            case SystemService.PHASE_BOOT_COMPLETED:
+                mBootCompleted.set(true);
+                break;
         }
     }
 
     /** lifecycle event */
     void handleUnlockUser(int userId) {
-        if (!FEATURE_ENABLED) {
-            return;
+        if (DEBUG) {
+            Slog.d(TAG, "handleUnlockUser: user=" + userId);
         }
         synchronized (mLock) {
             // Preload
@@ -450,9 +490,6 @@
 
     /** lifecycle event */
     void handleCleanupUser(int userId) {
-        if (!FEATURE_ENABLED) {
-            return;
-        }
         synchronized (mLock) {
             unloadUserLocked(userId);
         }
@@ -641,10 +678,10 @@
         out.endTag(null, tag);
     }
 
-    static void writeAttr(XmlSerializer out, String name, String value) throws IOException {
+    static void writeAttr(XmlSerializer out, String name, CharSequence value) throws IOException {
         if (TextUtils.isEmpty(value)) return;
 
-        out.attribute(null, name, value);
+        out.attribute(null, name, value.toString());
     }
 
     static void writeAttr(XmlSerializer out, String name, long value) throws IOException {
@@ -782,7 +819,7 @@
         out.setOutput(bos, StandardCharsets.UTF_8.name());
         out.startDocument(null, true);
 
-        getUserShortcutsLocked(userId).saveToXml(this, out, forBackup);
+        getUserShortcutsLocked(userId).saveToXml(out, forBackup);
 
         out.endDocument();
 
@@ -816,7 +853,9 @@
             return null;
         }
         try {
-            return loadUserInternal(userId, in, /* forBackup= */ false);
+            final ShortcutUser ret =  loadUserInternal(userId, in, /* forBackup= */ false);
+            cleanupDanglingBitmapDirectoriesLocked(userId, ret);
+            return ret;
         } catch (IOException|XmlPullParserException e) {
             Slog.e(TAG, "Failed to read file " + file.getBaseFile(), e);
             return null;
@@ -958,7 +997,7 @@
         if (userPackages == null) {
             userPackages = loadUserLocked(userId);
             if (userPackages == null) {
-                userPackages = new ShortcutUser(userId);
+                userPackages = new ShortcutUser(this, userId);
             }
             mUsers.put(userId, userPackages);
         }
@@ -976,7 +1015,7 @@
     @NonNull
     ShortcutPackage getPackageShortcutsLocked(
             @NonNull String packageName, @UserIdInt int userId) {
-        return getUserShortcutsLocked(userId).getPackageShortcuts(this, packageName);
+        return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
     }
 
     @GuardedBy("mLock")
@@ -985,7 +1024,7 @@
             @NonNull String packageName, @UserIdInt int ownerUserId,
             @UserIdInt int launcherUserId) {
         return getUserShortcutsLocked(ownerUserId)
-                .getLauncherShortcuts(this, packageName, launcherUserId);
+                .getLauncherShortcuts(packageName, launcherUserId);
     }
 
     // === Caller validation ===
@@ -1013,6 +1052,57 @@
         }
     }
 
+    private void cleanupDanglingBitmapDirectoriesLocked(
+            @UserIdInt int userId, @NonNull ShortcutUser user) {
+        if (DEBUG) {
+            Slog.d(TAG, "cleanupDanglingBitmaps: userId=" + userId);
+        }
+        final long start = injectElapsedRealtime();
+
+        final File bitmapDir = getUserBitmapFilePath(userId);
+        final File[] children = bitmapDir.listFiles();
+        if (children == null) {
+            return;
+        }
+        for (File child : children) {
+            if (!child.isDirectory()) {
+                continue;
+            }
+            final String packageName = child.getName();
+            if (DEBUG) {
+                Slog.d(TAG, "cleanupDanglingBitmaps: Found directory=" + packageName);
+            }
+            if (!user.hasPackage(packageName)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing dangling bitmap directory: " + packageName);
+                }
+                cleanupBitmapsForPackage(userId, packageName);
+            } else {
+                cleanupDanglingBitmapFilesLocked(userId, user, packageName, child);
+            }
+        }
+        logDurationStat(Stats.CLEANUP_DANGLING_BITMAPS, start);
+    }
+
+    private void cleanupDanglingBitmapFilesLocked(@UserIdInt int userId, @NonNull ShortcutUser user,
+            @NonNull String packageName, @NonNull File path) {
+        final ArraySet<String> usedFiles =
+                user.getPackageShortcuts(packageName).getUsedBitmapFiles();
+
+        for (File child : path.listFiles()) {
+            if (!child.isFile()) {
+                continue;
+            }
+            final String name = child.getName();
+            if (!usedFiles.contains(name)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Removing dangling bitmap file: " + child.getAbsolutePath());
+                }
+                child.delete();
+            }
+        }
+    }
+
     @VisibleForTesting
     static class FileOutputStreamWithPath extends FileOutputStream {
         private final File mFile;
@@ -1036,7 +1126,7 @@
     FileOutputStreamWithPath openIconFileForWrite(@UserIdInt int userId, ShortcutInfo shortcut)
             throws IOException {
         final File packagePath = new File(getUserBitmapFilePath(userId),
-                shortcut.getPackageName());
+                shortcut.getPackage());
         if (!packagePath.isDirectory()) {
             packagePath.mkdirs();
             if (!packagePath.isDirectory()) {
@@ -1075,7 +1165,6 @@
             }
 
             Bitmap bitmap;
-            Bitmap bitmapToRecycle = null;
             try {
                 switch (icon.getType()) {
                     case Icon.TYPE_RESOURCE: {
@@ -1127,9 +1216,6 @@
                     }
                 }
             } finally {
-                if (bitmapToRecycle != null) {
-                    bitmapToRecycle.recycle();
-                }
                 // Once saved, we won't use the original icon information, so null it out.
                 shortcut.clearIcon();
             }
@@ -1142,7 +1228,7 @@
     // so override in unit tests.
     // TODO CTS this case.
     void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
-        if (!shortcut.getPackageName().equals(icon.getResPackage())) {
+        if (!shortcut.getPackage().equals(icon.getResPackage())) {
             throw new IllegalArgumentException(
                     "Icon resource must reside in shortcut owner package");
         }
@@ -1246,15 +1332,23 @@
     }
 
     /**
-     * Throw if {@code numShortcuts} is bigger than {@link #mMaxDynamicShortcuts}.
+     * @throws IllegalArgumentException if {@code numShortcuts} is bigger than
+     * {@link #getMaxActivityShortcuts()}.
      */
-    void enforceMaxDynamicShortcuts(int numShortcuts) {
+    void enforceMaxActivityShortcuts(int numShortcuts) {
         if (numShortcuts > mMaxDynamicShortcuts) {
             throw new IllegalArgumentException("Max number of dynamic shortcuts exceeded");
         }
     }
 
     /**
+     * Return the max number of dynamic + manifest shortcuts for each launcher icon.
+     */
+    int getMaxActivityShortcuts() {
+        return mMaxDynamicShortcuts;
+    }
+
+    /**
      * - Sends a notification to LauncherApps
      * - Write to file
      */
@@ -1268,8 +1362,13 @@
     }
 
     private void notifyListeners(@NonNull String packageName, @UserIdInt int userId) {
-        if (!mUserManager.isUserRunning(userId)) {
-            return;
+        final long token = injectClearCallingIdentity();
+        try {
+            if (!mUserManager.isUserRunning(userId)) {
+                return;
+            }
+        } finally {
+            injectRestoreCallingIdentity(token);
         }
         postToHandler(() -> {
             final ArrayList<ShortcutChangeListener> copy;
@@ -1294,10 +1393,9 @@
      */
     private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate) {
         Preconditions.checkNotNull(shortcut, "Null shortcut detected");
-        if (shortcut.getActivityComponent() != null) {
+        if (shortcut.getActivity() != null) {
             Preconditions.checkState(
-                    shortcut.getPackageName().equals(
-                            shortcut.getActivityComponent().getPackageName()),
+                    shortcut.getPackage().equals(shortcut.getActivity().getPackageName()),
                     "Activity package name mismatch");
         }
 
@@ -1340,7 +1438,7 @@
         }
     }
 
-    private static void validateForXml(String s) {
+    private static void validateForXml(CharSequence s) {
         if (TextUtils.isEmpty(s)) {
             return;
         }
@@ -1368,11 +1466,14 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+
+            ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_SET);
+
             // Throttling.
-            if (!ps.tryApiCall(this)) {
+            if (!ps.tryApiCall()) {
                 return false;
             }
-            enforceMaxDynamicShortcuts(size);
 
             // Validate the shortcuts.
             for (int i = 0; i < size; i++) {
@@ -1380,15 +1481,18 @@
             }
 
             // First, remove all un-pinned; dynamic shortcuts
-            ps.deleteAllDynamicShortcuts(this);
+            ps.deleteAllDynamicShortcuts();
 
             // Then, add/update all.  We need to make sure to take over "pinned" flag.
             for (int i = 0; i < size; i++) {
                 final ShortcutInfo newShortcut = newShortcuts.get(i);
-                ps.addDynamicShortcut(this, newShortcut);
+                ps.addOrUpdateDynamicShortcut(newShortcut);
             }
         }
         packageShortcutsChanged(packageName, userId);
+
+        verifyStates();
+
         return true;
     }
 
@@ -1403,8 +1507,12 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+
+            ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_UPDATE);
+
             // Throttling.
-            if (!ps.tryApiCall(this)) {
+            if (!ps.tryApiCall()) {
                 return false;
             }
 
@@ -1414,11 +1522,22 @@
 
                 final ShortcutInfo target = ps.findShortcutById(source.getId());
                 if (target != null) {
+                    if (target.isEnabled() != source.isEnabled()) {
+                        Slog.w(TAG,
+                                "ShortcutInfo.enabled cannot be changed with updateShortcuts()");
+                    }
+
                     final boolean replacingIcon = (source.getIcon() != null);
                     if (replacingIcon) {
                         removeIcon(userId, target);
                     }
 
+                    if (source.getActivity() != null &&
+                            !source.getActivity().equals(target.getActivity())) {
+                        // TODO When activity is changing, check the dynamic count.
+                    }
+
+                    // Note copyNonNullFieldsFrom() does the "udpatable with?" check too.
                     target.copyNonNullFieldsFrom(source);
 
                     if (replacingIcon) {
@@ -1429,6 +1548,8 @@
         }
         packageShortcutsChanged(packageName, userId);
 
+        verifyStates();
+
         return true;
     }
 
@@ -1443,8 +1564,12 @@
         synchronized (mLock) {
             final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
 
+            ps.ensureImmutableShortcutsNotIncluded(newShortcuts);
+
+            ps.enforceShortcutCountsBeforeOperation(newShortcuts, OPERATION_ADD);
+
             // Throttling.
-            if (!ps.tryApiCall(this)) {
+            if (!ps.tryApiCall()) {
                 return false;
             }
             for (int i = 0; i < size; i++) {
@@ -1454,27 +1579,76 @@
                 fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
 
                 // Add it.
-                ps.addDynamicShortcut(this, newShortcut);
+                ps.addOrUpdateDynamicShortcut(newShortcut);
             }
         }
         packageShortcutsChanged(packageName, userId);
 
+        verifyStates();
+
         return true;
     }
 
     @Override
+    public void disableShortcuts(String packageName, List shortcutIds,
+            String disabledMessage, int disabledMessageResId, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+
+            for (int i = shortcutIds.size() - 1; i >= 0; i--) {
+                ps.disableWithId(Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)),
+                        disabledMessage, disabledMessageResId,
+                        /* overrideImmutable=*/ false);
+            }
+        }
+        packageShortcutsChanged(packageName, userId);
+
+        verifyStates();
+    }
+
+    @Override
+    public void enableShortcuts(String packageName, List shortcutIds, @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+
+            for (int i = shortcutIds.size() - 1; i >= 0; i--) {
+                ps.enableWithId((String) shortcutIds.get(i));
+            }
+        }
+        packageShortcutsChanged(packageName, userId);
+
+        verifyStates();
+    }
+
+    @Override
     public void removeDynamicShortcuts(String packageName, List shortcutIds,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
         Preconditions.checkNotNull(shortcutIds, "shortcutIds must be provided");
 
         synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+
+            ps.ensureImmutableShortcutsNotIncludedWithIds((List<String>) shortcutIds);
+
             for (int i = shortcutIds.size() - 1; i >= 0; i--) {
-                getPackageShortcutsLocked(packageName, userId).deleteDynamicWithId(this,
+                ps.deleteDynamicWithId(
                         Preconditions.checkStringNotEmpty((String) shortcutIds.get(i)));
             }
         }
         packageShortcutsChanged(packageName, userId);
+
+        verifyStates();
     }
 
     @Override
@@ -1482,9 +1656,11 @@
         verifyCaller(packageName, userId);
 
         synchronized (mLock) {
-            getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts(this);
+            getPackageShortcutsLocked(packageName, userId).deleteAllDynamicShortcuts();
         }
         packageShortcutsChanged(packageName, userId);
+
+        verifyStates();
     }
 
     @Override
@@ -1499,6 +1675,17 @@
     }
 
     @Override
+    public ParceledListSlice<ShortcutInfo> getManifestShortcuts(String packageName,
+            @UserIdInt int userId) {
+        verifyCaller(packageName, userId);
+        synchronized (mLock) {
+            return getShortcutsWithQueryLocked(
+                    packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR,
+                    ShortcutInfo::isManifestShortcut);
+        }
+    }
+
+    @Override
     public ParceledListSlice<ShortcutInfo> getPinnedShortcuts(String packageName,
             @UserIdInt int userId) {
         verifyCaller(packageName, userId);
@@ -1514,7 +1701,7 @@
 
         final ArrayList<ShortcutInfo> ret = new ArrayList<>();
 
-        getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags);
+        getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags);
 
         return new ParceledListSlice<>(ret);
     }
@@ -1533,7 +1720,7 @@
 
         synchronized (mLock) {
             return mMaxUpdatesPerInterval
-                    - getPackageShortcutsLocked(packageName, userId).getApiCallCount(this);
+                    - getPackageShortcutsLocked(packageName, userId).getApiCallCount();
         }
     }
 
@@ -1547,7 +1734,7 @@
     }
 
     @Override
-    public int getIconMaxDimensions(String packageName, int userId) throws RemoteException {
+    public int getIconMaxDimensions(String packageName, int userId) {
         verifyCaller(packageName, userId);
 
         synchronized (mLock) {
@@ -1555,6 +1742,34 @@
         }
     }
 
+    @Override
+    public void reportShortcutUsed(String packageName, String shortcutId, int userId) {
+        verifyCaller(packageName, userId);
+
+        Preconditions.checkNotNull(shortcutId);
+
+        if (DEBUG) {
+            Slog.d(TAG, String.format("reportShortcutUsed: Shortcut %s package %s used on user %d",
+                    shortcutId, packageName, userId));
+        }
+
+        synchronized (mLock) {
+            final ShortcutPackage ps = getPackageShortcutsLocked(packageName, userId);
+            if (ps.findShortcutById(shortcutId) == null) {
+                Log.w(TAG, String.format("reportShortcutUsed: package %s doesn't have shortcut %s",
+                        packageName, shortcutId));
+                return;
+            }
+        }
+
+        final long token = injectClearCallingIdentity();
+        try {
+            mUsageStatsManagerInternal.reportShortcutUsage(packageName, shortcutId, userId);
+        } finally {
+            injectRestoreCallingIdentity(token);
+        }
+    }
+
     /**
      * Reset all throttling, for developer options and command line.  Only system/shell can call it.
      */
@@ -1608,14 +1823,14 @@
     @VisibleForTesting
     boolean hasShortcutHostPermissionInner(@NonNull String callingPackage, int userId) {
         synchronized (mLock) {
-            final long start = System.currentTimeMillis();
+            final long start = injectElapsedRealtime();
 
             final ShortcutUser user = getUserShortcutsLocked(userId);
 
             final List<ResolveInfo> allHomeCandidates = new ArrayList<>();
 
             // Default launcher from package manager.
-            final long startGetHomeActivitiesAsUser = System.currentTimeMillis();
+            final long startGetHomeActivitiesAsUser = injectElapsedRealtime();
             final ComponentName defaultLauncher = injectPackageManagerInternal()
                     .getHomeActivitiesAsUser(allHomeCandidates, userId);
             logDurationStat(Stats.GET_DEFAULT_HOME, startGetHomeActivitiesAsUser);
@@ -1627,7 +1842,7 @@
                     Slog.v(TAG, "Default launcher from PM: " + detected);
                 }
             } else {
-                detected = user.getLauncherComponent();
+                detected = user.getDefaultLauncherComponent();
 
                 // TODO: Make sure it's still enabled.
                 if (DEBUG) {
@@ -1667,7 +1882,7 @@
                 if (DEBUG) {
                     Slog.v(TAG, "Detected launcher: " + detected);
                 }
-                user.setLauncherComponent(this, detected);
+                user.setDefaultLauncherComponent(detected);
                 return detected.getPackageName().equals(callingPackage);
             } else {
                 // Default launcher not found.
@@ -1701,7 +1916,7 @@
 
         // First, remove the package from the package list (if the package is a publisher).
         if (packageUserId == owningUserId) {
-            if (user.removePackage(this, packageName) != null) {
+            if (user.removePackage(packageName) != null) {
                 doNotify = true;
             }
         }
@@ -1714,7 +1929,7 @@
 
         // Now there may be orphan shortcuts because we removed pinned shortcuts at the previous
         // step.  Remove them too.
-        user.forAllPackages(p -> p.refreshPinnedFlags(this));
+        user.forAllPackages(p -> p.refreshPinnedFlags());
 
         scheduleSaveUser(owningUserId);
 
@@ -1740,17 +1955,17 @@
                 @Nullable ComponentName componentName,
                 int queryFlags, int userId) {
             final ArrayList<ShortcutInfo> ret = new ArrayList<>();
-            final int cloneFlag =
-                    ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) == 0)
-                            ? ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER
-                            : ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO;
+            final boolean cloneKeyFieldOnly =
+                    ((queryFlags & ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY) != 0);
+            final int cloneFlag = cloneKeyFieldOnly ? ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO
+                    : ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER;
             if (packageName == null) {
                 shortcutIds = null; // LauncherAppsService already threw for it though.
             }
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
-                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                        .attemptToRestoreIfNeededAndSave();
 
                 if (packageName != null) {
                     getShortcutsInnerLocked(launcherUserId,
@@ -1765,6 +1980,21 @@
                     });
                 }
             }
+            // Resolve all strings if needed.
+            if (!cloneKeyFieldOnly) {
+                final long token = injectClearCallingIdentity();
+                try {
+                    for (int i = ret.size() - 1; i >= 0; i--) {
+                        try {
+                            ret.get(i).resolveStringsRequiringCrossUser(mContext);
+                        } catch (NameNotFoundException e) {
+                            continue;
+                        }
+                    }
+                } finally {
+                    injectRestoreCallingIdentity(token);
+                }
+            }
             return ret;
         }
 
@@ -1775,7 +2005,13 @@
             final ArraySet<String> ids = shortcutIds == null ? null
                     : new ArraySet<>(shortcutIds);
 
-            getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret,
+            final ShortcutPackage p = getUserShortcutsLocked(userId)
+                    .getPackageShortcutsIfExists(packageName);
+            if (p == null) {
+                return; // No need to instantiate ShortcutPackage.
+            }
+
+            p.findAll(ret,
                     (ShortcutInfo si) -> {
                         if (si.getLastChangedTimestamp() < changedSince) {
                             return false;
@@ -1783,17 +2019,25 @@
                         if (ids != null && !ids.contains(si.getId())) {
                             return false;
                         }
-                        if (componentName != null
-                                && !componentName.equals(si.getActivityComponent())) {
-                            return false;
+                        if (componentName != null) {
+                            if (si.getActivity() != null
+                                    && !si.getActivity().equals(componentName)) {
+                                return false;
+                            }
                         }
-                        final boolean matchDynamic =
-                                ((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
-                                        && si.isDynamic();
-                        final boolean matchPinned =
-                                ((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
-                                        && si.isPinned();
-                        return matchDynamic || matchPinned;
+                        if (((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
+                                && si.isDynamic()) {
+                            return true;
+                        }
+                        if (((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
+                                && si.isPinned()) {
+                            return true;
+                        }
+                        if (((queryFlags & ShortcutQuery.FLAG_GET_MANIFEST) != 0)
+                                && si.isManifestShortcut()) {
+                            return true;
+                        }
+                        return false;
                     }, cloneFlag, callingPackage, launcherUserId);
         }
 
@@ -1805,7 +2049,7 @@
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
-                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                        .attemptToRestoreIfNeededAndSave();
 
                 final ShortcutInfo si = getShortcutInfoLocked(
                         launcherUserId, callingPackage, packageName, shortcutId, userId);
@@ -1819,9 +2063,14 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName");
             Preconditions.checkStringNotEmpty(shortcutId, "shortcutId");
 
+            final ShortcutPackage p = getUserShortcutsLocked(userId)
+                    .getPackageShortcutsIfExists(packageName);
+            if (p == null) {
+                return null;
+            }
+
             final ArrayList<ShortcutInfo> list = new ArrayList<>(1);
-            getPackageShortcutsLocked(packageName, userId).findAll(
-                    ShortcutService.this, list,
+            p.findAll(list,
                     (ShortcutInfo si) -> shortcutId.equals(si.getId()),
                     /* clone flags=*/ 0, callingPackage, launcherUserId);
             return list.size() == 0 ? null : list.get(0);
@@ -1838,12 +2087,13 @@
             synchronized (mLock) {
                 final ShortcutLauncher launcher =
                         getLauncherShortcutsLocked(callingPackage, userId, launcherUserId);
-                launcher.attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                launcher.attemptToRestoreIfNeededAndSave();
 
-                launcher.pinShortcuts(
-                        ShortcutService.this, userId, packageName, shortcutIds);
+                launcher.pinShortcuts(userId, packageName, shortcutIds);
             }
             packageShortcutsChanged(packageName, userId);
+
+            verifyStates();
         }
 
         @Override
@@ -1856,13 +2106,13 @@
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
-                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                        .attemptToRestoreIfNeededAndSave();
 
                 // Make sure the shortcut is actually visible to the launcher.
                 final ShortcutInfo si = getShortcutInfoLocked(
                         launcherUserId, callingPackage, packageName, shortcutId, userId);
                 // "si == null" should suffice here, but check the flags too just to make sure.
-                if (si == null || !(si.isDynamic() || si.isPinned())) {
+                if (si == null || !si.isEnabled() || !si.isAlive()) {
                     return null;
                 }
                 return si.getIntent();
@@ -1885,10 +2135,15 @@
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
-                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                        .attemptToRestoreIfNeededAndSave();
 
-                final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
-                        packageName, userId).findShortcutById(shortcutId);
+                final ShortcutPackage p = getUserShortcutsLocked(userId)
+                        .getPackageShortcutsIfExists(packageName);
+                if (p == null) {
+                    return 0;
+                }
+
+                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
                 return (shortcutInfo != null && shortcutInfo.hasIconResource())
                         ? shortcutInfo.getIconResourceId() : 0;
             }
@@ -1904,10 +2159,15 @@
 
             synchronized (mLock) {
                 getLauncherShortcutsLocked(callingPackage, userId, launcherUserId)
-                        .attemptToRestoreIfNeededAndSave(ShortcutService.this);
+                        .attemptToRestoreIfNeededAndSave();
 
-                final ShortcutInfo shortcutInfo = getPackageShortcutsLocked(
-                        packageName, userId).findShortcutById(shortcutId);
+                final ShortcutPackage p = getUserShortcutsLocked(userId)
+                        .getPackageShortcutsIfExists(packageName);
+                if (p == null) {
+                    return null;
+                }
+
+                final ShortcutInfo shortcutInfo = p.findShortcutById(shortcutId);
                 if (shortcutInfo == null || !shortcutInfo.hasIconFile()) {
                     return null;
                 }
@@ -1938,9 +2198,6 @@
          */
         @Override
         public void onSystemLocaleChangedNoLock() {
-            if (!FEATURE_ENABLED) {
-                return;
-            }
             // DO NOT HOLD ANY LOCKS HERE.
 
             // We want to reset throttling for all packages for all users.  But we can't just do so
@@ -1953,8 +2210,15 @@
             //
             // This allows ShortcutUser's to detect the system locale change, so they can reset
             // counters.
-            mLocaleChangeSequenceNumber.incrementAndGet();
-            postToHandler(() -> scheduleSaveBaseState());
+
+            // Ignore all callback during system boot.
+            if (mBootCompleted.get()) {
+                mLocaleChangeSequenceNumber.incrementAndGet();
+                if (DEBUG) {
+                    Slog.d(TAG, "onSystemLocaleChangedNoLock: " + mLocaleChangeSequenceNumber.get());
+                }
+                postToHandler(() -> scheduleSaveBaseState());
+            }
         }
     }
 
@@ -1995,31 +2259,37 @@
         if (DEBUG) {
             Slog.d(TAG, "checkPackageChanges() ownerUserId=" + ownerUserId);
         }
-        final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
 
-        synchronized (mLock) {
-            final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
+        final long start = injectElapsedRealtime();
+        try {
+            final ArrayList<PackageWithUser> gonePackages = new ArrayList<>();
 
-            user.forAllPackageItems(spi -> {
-                if (spi.getPackageInfo().isShadow()) {
-                    return; // Don't delete shadow information.
+            synchronized (mLock) {
+                final ShortcutUser user = getUserShortcutsLocked(ownerUserId);
+
+                // Find packages that have been uninstalled.
+                user.forAllPackageItems(spi -> {
+                    if (spi.getPackageInfo().isShadow()) {
+                        return; // Don't delete shadow information.
+                    }
+                    if (!isPackageInstalled(spi.getPackageName(), spi.getPackageUserId())) {
+                        gonePackages.add(PackageWithUser.of(spi));
+                    }
+                });
+                if (gonePackages.size() > 0) {
+                    for (int i = gonePackages.size() - 1; i >= 0; i--) {
+                        final PackageWithUser pu = gonePackages.get(i);
+                        cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
+                    }
                 }
-                final int versionCode = getApplicationVersionCode(
-                        spi.getPackageName(), spi.getPackageUserId());
-                if (versionCode >= 0) {
-                    // Package still installed, see if it's updated.
-                    getUserShortcutsLocked(ownerUserId).handlePackageUpdated(
-                            this, spi.getPackageName(), versionCode);
-                } else {
-                    gonePackages.add(PackageWithUser.of(spi));
-                }
-            });
-            if (gonePackages.size() > 0) {
-                for (int i = gonePackages.size() - 1; i >= 0; i--) {
-                    final PackageWithUser pu = gonePackages.get(i);
-                    cleanUpPackageLocked(pu.packageName, ownerUserId, pu.userId);
-                }
+
+                // Then for each installed app, publish manifest shortcuts when needed.
+                forInstalledApplications(ownerUserId, ai -> {
+                    user.handlePackageAddedOrUpdated(ai.packageName);
+                });
             }
+        } finally {
+            logDurationStat(Stats.CHECK_PACKAGE_CHANGES, start);
         }
     }
 
@@ -2028,8 +2298,9 @@
             Slog.d(TAG, String.format("handlePackageAdded: %s user=%d", packageName, userId));
         }
         synchronized (mLock) {
-            forEachLoadedUserLocked(user ->
-                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
+            user.handlePackageAddedOrUpdated(packageName);
         }
     }
 
@@ -2039,14 +2310,12 @@
                     packageName, userId));
         }
         synchronized (mLock) {
-            forEachLoadedUserLocked(user ->
-                    user.attemptToRestoreIfNeededAndSave(this, packageName, userId));
+            final ShortcutUser user = getUserShortcutsLocked(userId);
+            user.attemptToRestoreIfNeededAndSave(this, packageName, userId);
 
-            final int versionCode = getApplicationVersionCode(packageName, userId);
-            if (versionCode < 0) {
-                return; // shouldn't happen
+            if (isPackageInstalled(packageName, userId)) {
+                user.handlePackageAddedOrUpdated(packageName);
             }
-            getUserShortcutsLocked(userId).handlePackageUpdated(this, packageName, versionCode);
         }
     }
 
@@ -2068,10 +2337,16 @@
 
     // === PackageManager interaction ===
 
+    @Nullable
     PackageInfo getPackageInfoWithSignatures(String packageName, @UserIdInt int userId) {
         return injectPackageInfo(packageName, userId, true);
     }
 
+    @Nullable
+    PackageInfo getPackageInfo(String packageName, @UserIdInt int userId) {
+        return injectPackageInfo(packageName, userId, false);
+    }
+
     int injectGetPackageUid(@NonNull String packageName, @UserIdInt int userId) {
         final long token = injectClearCallingIdentity();
         try {
@@ -2086,10 +2361,11 @@
         }
     }
 
+    @Nullable
     @VisibleForTesting
     PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
             boolean getSignatures) {
-        final long start = System.currentTimeMillis();
+        final long start = injectElapsedRealtime();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getPackageInfo(packageName, PACKAGE_MATCH_FLAGS
@@ -2108,9 +2384,10 @@
         }
     }
 
+    @Nullable
     @VisibleForTesting
     ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
-        final long start = System.currentTimeMillis();
+        final long start = injectElapsedRealtime();
         final long token = injectClearCallingIdentity();
         try {
             return mIPackageManager.getApplicationInfo(packageName, PACKAGE_MATCH_FLAGS, userId);
@@ -2125,6 +2402,61 @@
         }
     }
 
+    @Nullable
+    @VisibleForTesting
+    PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
+        final long start = injectElapsedRealtime();
+        final long token = injectClearCallingIdentity();
+        try {
+            return mIPackageManager.getPackageInfo(packageName,
+                    PACKAGE_MATCH_FLAGS | PackageManager.GET_ACTIVITIES
+                            | PackageManager.GET_META_DATA, userId);
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return null;
+        } finally {
+            injectRestoreCallingIdentity(token);
+
+            logDurationStat(Stats.GET_ACTIVITIES_WITH_METADATA, start);
+        }
+    }
+
+    @Nullable
+    @VisibleForTesting
+    List<ApplicationInfo> injectInstalledApplications(@UserIdInt int userId) {
+        final long start = injectElapsedRealtime();
+        final long token = injectClearCallingIdentity();
+        try {
+            final ParceledListSlice<ApplicationInfo> parceledList =
+                    mIPackageManager.getInstalledApplications(PACKAGE_MATCH_FLAGS, userId);
+            if (parceledList == null) {
+                return Collections.emptyList();
+            }
+            return parceledList.getList();
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+            Slog.wtf(TAG, "RemoteException", e);
+            return null;
+        } finally {
+            injectRestoreCallingIdentity(token);
+
+            logDurationStat(Stats.GET_INSTALLED_APPLICATIONS, start);
+        }
+    }
+
+    private void forInstalledApplications(@UserIdInt int userId,
+            Consumer<ApplicationInfo> callback) {
+        final List<ApplicationInfo> list = injectInstalledApplications(userId);
+        for (int i = list.size() - 1; i >= 0; i--) {
+            final ApplicationInfo ai = list.get(i);
+
+            if ((ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
+                callback.accept(ai);
+            }
+        }
+    }
+
     private boolean isApplicationFlagSet(String packageName, int userId, int flags) {
         final ApplicationInfo ai = injectApplicationInfo(packageName, userId);
         return (ai != null) && ((ai.flags & flags) == flags);
@@ -2134,15 +2466,10 @@
         return isApplicationFlagSet(packageName, userId, ApplicationInfo.FLAG_INSTALLED);
     }
 
-    /**
-     * @return the version code of the package, or -1 if the app is not installed.
-     */
-    int getApplicationVersionCode(String packageName, int userId) {
-        final ApplicationInfo ai = injectApplicationInfo(packageName, userId);
-        if ((ai == null) || ((ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
-            return -1;
-        }
-        return ai.versionCode;
+    @Nullable
+    XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
+// TODO Doesn't seem like ACROSS_USER is needed, but double check.
+        return activityInfo.loadXmlMetaData(mContext.getPackageManager(), key);
     }
 
     // === Backup & restore ===
@@ -2168,7 +2495,7 @@
                 return null;
             }
 
-            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave(this));
+            user.forAllPackageItems(spi -> spi.refreshPackageInfoAndSave());
 
             // Then save.
             final ByteArrayOutputStream os = new ByteArrayOutputStream(32 * 1024);
@@ -2283,11 +2610,15 @@
                 dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO, "getPackageInfo()");
                 dumpStatLS(pw, p, Stats.GET_PACKAGE_INFO_WITH_SIG, "getPackageInfo(SIG)");
                 dumpStatLS(pw, p, Stats.GET_APPLICATION_INFO, "getApplicationInfo");
+                dumpStatLS(pw, p, Stats.CLEANUP_DANGLING_BITMAPS, "cleanupDanglingBitmaps");
+                dumpStatLS(pw, p, Stats.GET_ACTIVITIES_WITH_METADATA, "getActivities+metadata");
+                dumpStatLS(pw, p, Stats.GET_INSTALLED_APPLICATIONS, "getInstalledApplications");
+                dumpStatLS(pw, p, Stats.CHECK_PACKAGE_CHANGES, "checkPackageChanges");
             }
 
             for (int i = 0; i < mUsers.size(); i++) {
                 pw.println();
-                mUsers.valueAt(i).dump(this, pw, "  ");
+                mUsers.valueAt(i).dump(pw, "  ");
             }
 
             pw.println();
@@ -2499,8 +2830,7 @@
 
         private void clearLauncher() {
             synchronized (mLock) {
-                getUserShortcutsLocked(mUserId).setLauncherComponent(
-                        ShortcutService.this, null);
+                getUserShortcutsLocked(mUserId).setDefaultLauncherComponent(null);
             }
         }
 
@@ -2510,7 +2840,7 @@
                 hasShortcutHostPermissionInner("-", mUserId);
 
                 getOutPrintWriter().println("Launcher: "
-                        + getUserShortcutsLocked(mUserId).getLauncherComponent());
+                        + getUserShortcutsLocked(mUserId).getDefaultLauncherComponent());
             }
         }
 
@@ -2663,15 +2993,47 @@
     }
 
     @VisibleForTesting
-    ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
+    ShortcutPackage getPackageShortcutForTest(String packageName, int userId) {
         synchronized (mLock) {
             final ShortcutUser user = mUsers.get(userId);
             if (user == null) return null;
 
-            final ShortcutPackage pkg = user.getAllPackagesForTest().get(packageName);
+            return user.getAllPackagesForTest().get(packageName);
+        }
+    }
+
+    @VisibleForTesting
+    ShortcutInfo getPackageShortcutForTest(String packageName, String shortcutId, int userId) {
+        synchronized (mLock) {
+            final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
             if (pkg == null) return null;
 
             return pkg.findShortcutById(shortcutId);
         }
     }
+
+    /**
+     * Control whether {@link #verifyStates} should be performed.  We always perform it during unit
+     * tests.
+     */
+    @VisibleForTesting
+    boolean injectShouldPerformVerification() {
+        return DEBUG;
+    }
+
+    /**
+     * Check various internal states and throws if there's any inconsistency.
+     * This is normally only enabled during unit tests.
+     */
+    final void verifyStates() {
+        if (injectShouldPerformVerification()) {
+            verifyStatesInner();
+        }
+    }
+
+    private void verifyStatesInner() {
+        synchronized (this) {
+            forEachLoadedUserLocked(u -> u.forAllPackageItems(ShortcutPackageItem::verifyStates));
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 7d19a78..840c3df 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -16,6 +16,7 @@
 package com.android.server.pm;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.content.ComponentName;
 import android.text.format.Formatter;
@@ -23,6 +24,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
@@ -39,6 +41,8 @@
 
 /**
  * User information used by {@link ShortcutService}.
+ *
+ * All methods should be guarded by {@code #mService.mLock}.
  */
 class ShortcutUser {
     private static final String TAG = ShortcutService.TAG;
@@ -87,6 +91,8 @@
         }
     }
 
+    final ShortcutService mService;
+
     @UserIdInt
     private final int mUserId;
 
@@ -97,11 +103,12 @@
     private final ArrayMap<PackageWithUser, ShortcutLauncher> mLaunchers = new ArrayMap<>();
 
     /** Default launcher that can access the launcher apps APIs. */
-    private ComponentName mLauncherComponent;
+    private ComponentName mDefaultLauncherComponent;
 
     private long mKnownLocaleChangeSequenceNumber;
 
-    public ShortcutUser(int userId) {
+    public ShortcutUser(ShortcutService service, int userId) {
+        mService = service;
         mUserId = userId;
     }
 
@@ -116,10 +123,14 @@
         return mPackages;
     }
 
-    public ShortcutPackage removePackage(@NonNull ShortcutService s, @NonNull String packageName) {
+    public boolean hasPackage(@NonNull String packageName) {
+        return mPackages.containsKey(packageName);
+    }
+
+    public ShortcutPackage removePackage(@NonNull String packageName) {
         final ShortcutPackage removed = mPackages.remove(packageName);
 
-        s.cleanupBitmapsForPackage(mUserId, packageName);
+        mService.cleanupBitmapsForPackage(mUserId, packageName);
 
         return removed;
     }
@@ -136,23 +147,33 @@
                 launcher.getPackageName()), launcher);
     }
 
+    @Nullable
     public ShortcutLauncher removeLauncher(
             @UserIdInt int packageUserId, @NonNull String packageName) {
         return mLaunchers.remove(PackageWithUser.of(packageUserId, packageName));
     }
 
-    public ShortcutPackage getPackageShortcuts(ShortcutService s, @NonNull String packageName) {
-        ShortcutPackage ret = mPackages.get(packageName);
-        if (ret == null) {
-            ret = new ShortcutPackage(s, this, mUserId, packageName);
-            mPackages.put(packageName, ret);
-        } else {
-            ret.attemptToRestoreIfNeededAndSave(s);
+    @Nullable
+    public ShortcutPackage getPackageShortcutsIfExists(@NonNull String packageName) {
+        final ShortcutPackage ret = mPackages.get(packageName);
+        if (ret != null) {
+            ret.attemptToRestoreIfNeededAndSave();
         }
         return ret;
     }
 
-    public ShortcutLauncher getLauncherShortcuts(ShortcutService s, @NonNull String packageName,
+    @NonNull
+    public ShortcutPackage getPackageShortcuts(@NonNull String packageName) {
+        ShortcutPackage ret = getPackageShortcutsIfExists(packageName);
+        if (ret == null) {
+            ret = new ShortcutPackage(this, mUserId, packageName);
+            mPackages.put(packageName, ret);
+        }
+        return ret;
+    }
+
+    @NonNull
+    public ShortcutLauncher getLauncherShortcuts(@NonNull String packageName,
             @UserIdInt int launcherUserId) {
         final PackageWithUser key = PackageWithUser.of(launcherUserId, packageName);
         ShortcutLauncher ret = mLaunchers.get(key);
@@ -160,7 +181,7 @@
             ret = new ShortcutLauncher(this, mUserId, packageName, launcherUserId);
             mLaunchers.put(key, ret);
         } else {
-            ret.attemptToRestoreIfNeededAndSave(s);
+            ret.attemptToRestoreIfNeededAndSave();
         }
         return ret;
     }
@@ -197,8 +218,8 @@
     /**
      * Reset all throttling counters for all packages, if there has been a system locale change.
      */
-    public void resetThrottlingIfNeeded(ShortcutService s) {
-        final long currentNo = s.getLocaleChangeSequenceNumber();
+    public void resetThrottlingIfNeeded() {
+        final long currentNo = mService.getLocaleChangeSequenceNumber();
         if (mKnownLocaleChangeSequenceNumber < currentNo) {
             if (ShortcutService.DEBUG) {
                 Slog.d(TAG, "LocaleChange detected for user " + mUserId);
@@ -206,31 +227,32 @@
 
             mKnownLocaleChangeSequenceNumber = currentNo;
 
-            forAllPackages(p -> p.resetRateLimiting(s));
+            forAllPackages(p -> p.resetRateLimiting());
 
-            s.scheduleSaveUser(mUserId);
+            mService.scheduleSaveUser(mUserId);
         }
     }
 
-    /**
-     * Called when a package is updated.
-     */
-    public void handlePackageUpdated(ShortcutService s, @NonNull String packageName,
-            int newVersionCode) {
-        if (!mPackages.containsKey(packageName)) {
-            return;
+    public void handlePackageAddedOrUpdated(@NonNull String packageName) {
+        final boolean isNewApp = !mPackages.containsKey(packageName);
+
+        final ShortcutPackage shortcutPackage = getPackageShortcuts(packageName);
+
+        if (!shortcutPackage.handlePackageAddedOrUpdated(isNewApp)) {
+            if (isNewApp) {
+                mPackages.remove(packageName);
+            }
         }
-        getPackageShortcuts(s, packageName).handlePackageUpdated(s, newVersionCode);
     }
 
     public void attemptToRestoreIfNeededAndSave(ShortcutService s, @NonNull String packageName,
             @UserIdInt int packageUserId) {
         forPackageItem(packageName, packageUserId, spi -> {
-            spi.attemptToRestoreIfNeededAndSave(s);
+            spi.attemptToRestoreIfNeededAndSave();
         });
     }
 
-    public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
+    public void saveToXml(XmlSerializer out, boolean forBackup)
             throws IOException, XmlPullParserException {
         out.startTag(null, TAG_ROOT);
 
@@ -238,29 +260,29 @@
                 mKnownLocaleChangeSequenceNumber);
 
         ShortcutService.writeTagValue(out, TAG_LAUNCHER,
-                mLauncherComponent);
+                mDefaultLauncherComponent);
 
         // Can't use forEachPackageItem due to the checked exceptions.
         {
             final int size = mLaunchers.size();
             for (int i = 0; i < size; i++) {
-                saveShortcutPackageItem(s, out, mLaunchers.valueAt(i), forBackup);
+                saveShortcutPackageItem(out, mLaunchers.valueAt(i), forBackup);
             }
         }
         {
             final int size = mPackages.size();
             for (int i = 0; i < size; i++) {
-                saveShortcutPackageItem(s, out, mPackages.valueAt(i), forBackup);
+                saveShortcutPackageItem(out, mPackages.valueAt(i), forBackup);
             }
         }
 
         out.endTag(null, TAG_ROOT);
     }
 
-    private void saveShortcutPackageItem(ShortcutService s, XmlSerializer out,
+    private void saveShortcutPackageItem(XmlSerializer out,
             ShortcutPackageItem spi, boolean forBackup) throws IOException, XmlPullParserException {
         if (forBackup) {
-            if (!s.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
+            if (!mService.shouldBackupApp(spi.getPackageName(), spi.getPackageUserId())) {
                 return; // Don't save.
             }
             if (spi.getPackageUserId() != spi.getOwnerUserId()) {
@@ -272,7 +294,7 @@
 
     public static ShortcutUser loadFromXml(ShortcutService s, XmlPullParser parser, int userId,
             boolean fromBackup) throws IOException, XmlPullParserException {
-        final ShortcutUser ret = new ShortcutUser(userId);
+        final ShortcutUser ret = new ShortcutUser(s, userId);
 
         ret.mKnownLocaleChangeSequenceNumber = ShortcutService.parseLongAttribute(parser,
                 ATTR_KNOWN_LOCALE_CHANGE_SEQUENCE_NUMBER);
@@ -290,7 +312,7 @@
             if (depth == outerDepth + 1) {
                 switch (tag) {
                     case TAG_LAUNCHER: {
-                        ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
+                        ret.mDefaultLauncherComponent = ShortcutService.parseComponentNameAttribute(
                                 parser, ATTR_VALUE);
                         continue;
                     }
@@ -315,16 +337,16 @@
         return ret;
     }
 
-    public ComponentName getLauncherComponent() {
-        return mLauncherComponent;
+    public ComponentName getDefaultLauncherComponent() {
+        return mDefaultLauncherComponent;
     }
 
-    public void setLauncherComponent(ShortcutService s, ComponentName launcherComponent) {
-        if (Objects.equal(mLauncherComponent, launcherComponent)) {
+    public void setDefaultLauncherComponent(ComponentName launcherComponent) {
+        if (Objects.equal(mDefaultLauncherComponent, launcherComponent)) {
             return;
         }
-        mLauncherComponent = launcherComponent;
-        s.scheduleSaveUser(mUserId);
+        mDefaultLauncherComponent = launcherComponent;
+        mService.scheduleSaveUser(mUserId);
     }
 
     public void resetThrottling() {
@@ -333,7 +355,7 @@
         }
     }
 
-    public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+    public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
         pw.print(prefix);
         pw.print("User: ");
         pw.print(mUserId);
@@ -345,24 +367,24 @@
 
         pw.print(prefix);
         pw.print("Default launcher: ");
-        pw.print(mLauncherComponent);
+        pw.print(mDefaultLauncherComponent);
         pw.println();
 
         for (int i = 0; i < mLaunchers.size(); i++) {
-            mLaunchers.valueAt(i).dump(s, pw, prefix);
+            mLaunchers.valueAt(i).dump(pw, prefix);
         }
 
         for (int i = 0; i < mPackages.size(); i++) {
-            mPackages.valueAt(i).dump(s, pw, prefix);
+            mPackages.valueAt(i).dump(pw, prefix);
         }
 
         pw.println();
         pw.print(prefix);
         pw.println("Bitmap directories: ");
-        dumpDirectorySize(s, pw, prefix + "  ", s.getUserBitmapFilePath(mUserId));
+        dumpDirectorySize(pw, prefix + "  ", mService.getUserBitmapFilePath(mUserId));
     }
 
-    private void dumpDirectorySize(@NonNull ShortcutService s, @NonNull PrintWriter pw,
+    private void dumpDirectorySize(@NonNull PrintWriter pw,
             @NonNull String prefix, File path) {
         int numFiles = 0;
         long size = 0;
@@ -373,7 +395,7 @@
                     numFiles++;
                     size += child.length();
                 } else if (child.isDirectory()) {
-                    dumpDirectorySize(s, pw, prefix + "  ", child);
+                    dumpDirectorySize(pw, prefix + "  ", child);
                 }
             }
         }
@@ -385,7 +407,7 @@
         pw.print(" files, size=");
         pw.print(size);
         pw.print(" (");
-        pw.print(Formatter.formatFileSize(s.mContext, size));
+        pw.print(Formatter.formatFileSize(mService.mContext, size));
         pw.println(")");
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index b916790..95689ca 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,10 +27,12 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
+import android.app.AppGlobals;
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
 import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -67,6 +69,7 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.OsConstants;
+import android.text.TextUtils;
 import android.util.AtomicFile;
 import android.util.IntArray;
 import android.util.Log;
@@ -414,7 +417,9 @@
             // user restriction was not a default guest restriction.
             setUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, true, currentGuestUser.id);
         }
-    }
+
+        maybeInitializeDemoMode(UserHandle.USER_SYSTEM);
+}
 
     @Override
     public String getUserAccount(int userId) {
@@ -2030,6 +2035,7 @@
         final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
         final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
         final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
+        final boolean isDemo = (flags & UserInfo.FLAG_DEMO) != 0;
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo;
         UserData userData;
@@ -2047,8 +2053,8 @@
                     Log.e(LOG_TAG, "Cannot add more managed profiles for user " + parentId);
                     return null;
                 }
-                if (!isGuest && !isManagedProfile && isUserLimitReached()) {
-                    // If we're not adding a guest user or a managed profile and the limit has
+                if (!isGuest && !isManagedProfile && !isDemo && isUserLimitReached()) {
+                    // If we're not adding a guest/demo user or a managed profile and the limit has
                     // been reached, cannot add a user.
                     return null;
                 }
@@ -2074,7 +2080,8 @@
                         return null;
                     }
                 }
-                if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0) {
+                if (!UserManager.isSplitSystemUser() && (flags & UserInfo.FLAG_EPHEMERAL) != 0
+                        && (flags & UserInfo.FLAG_DEMO) == 0) {
                     Log.e(LOG_TAG,
                             "Ephemeral users are supported on split-system-user systems only.");
                     return null;
@@ -2716,6 +2723,8 @@
                 mPm.onBeforeUserStartUninitialized(userId);
             }
         }
+
+        maybeInitializeDemoMode(userId);
     }
 
     /**
@@ -2730,6 +2739,7 @@
 
     /**
      * Make a note of the last started time of a user and do some cleanup.
+     * This is called with ActivityManagerService lock held.
      * @param userId the user that was just foregrounded
      */
     public void onUserLoggedIn(@UserIdInt int userId) {
@@ -2747,6 +2757,24 @@
         scheduleWriteUser(userData);
     }
 
+    private void maybeInitializeDemoMode(int userId) {
+        if (UserManager.isDeviceInDemoMode(mContext)) {
+            String demoLauncher =
+                    mContext.getResources().getString(
+                            com.android.internal.R.string.config_demoModeLauncherComponent);
+            if (!TextUtils.isEmpty(demoLauncher)) {
+                ComponentName componentToEnable = ComponentName.unflattenFromString(demoLauncher);
+                try {
+                    AppGlobals.getPackageManager().setComponentEnabledSetting(componentToEnable,
+                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, /* flags= */ 0,
+                            /* userId= */ userId);
+                } catch (RemoteException re) {
+                    // Internal, shouldn't happen
+                }
+            }
+        }
+    }
+
     /**
      * Returns the next available user id, filling in any holes in the ids.
      * TODO: May not be a good idea to recycle ids, in case it results in confusion
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 38a3f42..414d165 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -33,6 +33,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
@@ -424,6 +425,14 @@
                             android.provider.Settings.Global.SAFE_BOOT_DISALLOWED,
                             newValue ? 1 : 0);
                     break;
+                case UserManager.DISALLOW_FACTORY_RESET:
+                    if (newValue) {
+                        PersistentDataBlockManager manager = (PersistentDataBlockManager) context
+                                .getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
+                        if (manager != null) {
+                            manager.setOemUnlockEnabled(false);
+                        }
+                    }
             }
         } finally {
             Binder.restoreCallingIdentity(id);
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index 5ef518e..6fc15f0 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -1145,7 +1145,7 @@
         public GlobalActionsDialog(Context context, AlertParams params) {
             super(context, getDialogTheme(context));
             mContext = getContext();
-            mAlert = new AlertController(mContext, this, getWindow());
+            mAlert = AlertController.create(mContext, this, getWindow());
             mAdapter = (MyAdapter) params.mAdapter;
             mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
             params.apply(mAlert);
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index a77d512..2e32fe3 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -30,6 +30,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.Settings;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
@@ -142,7 +143,8 @@
             if (!disabled
                     && (DEBUG_SHOW_EVERY_TIME || !mConfirmed)
                     && userSetupComplete
-                    && !mVrModeEnabled) {
+                    && !mVrModeEnabled
+                    && !UserManager.isDeviceInDemoMode(mContext)) {
                 mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
             }
         } else {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6987744..e0cfe4e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -4386,6 +4386,8 @@
             } else {
                 vf.set(cf);
             }
+        } else if (attrs.type == TYPE_WALLPAPER) {
+           layoutWallpaper(win, pf, df, of, cf);
         } else if (win == mStatusBar) {
             pf.left = df.left = of.left = mUnrestrictedScreenLeft;
             pf.top = df.top = of.top = mUnrestrictedScreenTop;
@@ -4609,17 +4611,6 @@
                             + mOverscanScreenWidth;
                     pf.bottom = df.bottom = of.bottom = cf.bottom = mOverscanScreenTop
                             + mOverscanScreenHeight;
-                } else if (attrs.type == TYPE_WALLPAPER) {
-                    // The wallpaper also has Real Ultimate Power, but we want to tell
-                    // it about the overscan area.
-                    pf.left = df.left = mOverscanScreenLeft;
-                    pf.top = df.top = mOverscanScreenTop;
-                    pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
-                    pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
-                    of.left = cf.left = mUnrestrictedScreenLeft;
-                    of.top = cf.top = mUnrestrictedScreenTop;
-                    of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
-                    of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
                 } else if ((fl & FLAG_LAYOUT_IN_OVERSCAN) != 0
                         && attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                         && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
@@ -4812,6 +4803,20 @@
         }
     }
 
+    private void layoutWallpaper(WindowState win, Rect pf, Rect df, Rect of, Rect cf) {
+
+        // The wallpaper also has Real Ultimate Power, but we want to tell
+        // it about the overscan area.
+        pf.left = df.left = mOverscanScreenLeft;
+        pf.top = df.top = mOverscanScreenTop;
+        pf.right = df.right = mOverscanScreenLeft + mOverscanScreenWidth;
+        pf.bottom = df.bottom = mOverscanScreenTop + mOverscanScreenHeight;
+        of.left = cf.left = mUnrestrictedScreenLeft;
+        of.top = cf.top = mUnrestrictedScreenTop;
+        of.right = cf.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth;
+        of.bottom = cf.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight;
+    }
+
     private void offsetInputMethodWindowLw(WindowState win) {
         int top = Math.max(win.getDisplayFrameLw().top, win.getContentFrameLw().top);
         top += win.getGivenContentInsetsLw().top;
@@ -4993,7 +4998,7 @@
 
         // Keep track of the window if it's dimming but not necessarily fullscreen.
         final boolean reallyVisible = win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw();
-        if (mTopFullscreenOpaqueOrDimmingWindowState == null &&  reallyVisible
+        if (mTopFullscreenOpaqueOrDimmingWindowState == null && reallyVisible
                 && win.isDimming() && StackId.normallyFullscreenWindows(stackId)) {
             mTopFullscreenOpaqueOrDimmingWindowState = win;
         }
@@ -5651,6 +5656,17 @@
                 break;
             }
 
+            case KeyEvent.KEYCODE_FP_NAV_DOWN:
+                // fall through
+            case KeyEvent.KEYCODE_FP_NAV_UP:
+                // fall through
+            case KeyEvent.KEYCODE_FP_NAV_LEFT:
+                // fall through
+            case KeyEvent.KEYCODE_FP_NAV_RIGHT: {
+                interceptStatusBarKey(event);
+                break;
+            }
+
             case KeyEvent.KEYCODE_SLEEP: {
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false;
@@ -5772,6 +5788,32 @@
     }
 
     /**
+     * Handle statusbar expansion events.
+     * @param event
+     */
+    private void interceptStatusBarKey(KeyEvent event) {
+        final int e = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_UP) {
+            boolean doOpen = false;
+            boolean doClose = false;
+            doOpen = (e == KeyEvent.KEYCODE_FP_NAV_DOWN);
+            doClose = (e == KeyEvent.KEYCODE_FP_NAV_UP);
+            IStatusBarService sbar = getStatusBarService();
+            if (sbar != null) {
+                try {
+                    if (doOpen) {
+                        sbar.expandNotificationsPanel();
+                    } else if (doClose) {
+                        sbar.collapsePanels();
+                    }
+                } catch (RemoteException e1) {
+                    // oops, no statusbar. Ignore event.
+                }
+            }
+        }
+    }
+
+    /**
      * Returns true if the key can have global actions attached to it.
      * We reserve all power management keys for the system since they require
      * very careful handling.
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index a32c017..8ef0acb 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -49,6 +49,7 @@
             "debug.orientation.log", false);
 
     private static final boolean USE_GRAVITY_SENSOR = false;
+    private static final int DEFAULT_BATCH_LATENCY = 100000;
 
     private Handler mHandler;
     private SensorManager mSensorManager;
@@ -118,7 +119,12 @@
                     Slog.d(TAG, "WindowOrientationListener enabled");
                 }
                 mOrientationJudge.resetLocked();
-                mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
+                if (mSensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+                    mSensorManager.registerListener(
+                            mOrientationJudge, mSensor, mRate, DEFAULT_BATCH_LATENCY, mHandler);
+                } else {
+                    mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
+                }
                 mEnabled = true;
             }
         }
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index 7108f4a..3ed6ec9 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -23,6 +23,7 @@
 import com.android.internal.app.IBatteryStats;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.am.RetailDemoModeServiceInternal;
 
 import android.app.ActivityManagerNative;
 import android.content.BroadcastReceiver;
@@ -91,6 +92,7 @@
     private final ActivityManagerInternal mActivityManagerInternal;
     private final InputManagerInternal mInputManagerInternal;
     private final InputMethodManagerInternal mInputMethodManagerInternal;
+    private final RetailDemoModeServiceInternal mRetailDemoModeServiceInternal;
 
     private final NotifierHandler mHandler;
     private final Intent mScreenOnIntent;
@@ -136,6 +138,7 @@
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         mInputMethodManagerInternal = LocalServices.getService(InputMethodManagerInternal.class);
+        mRetailDemoModeServiceInternal = LocalServices.getService(RetailDemoModeServiceInternal.class);
 
         mHandler = new NotifierHandler(looper);
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
@@ -534,7 +537,9 @@
             }
             mUserActivityPending = false;
         }
-
+        if (mRetailDemoModeServiceInternal != null) {
+            mRetailDemoModeServiceInternal.onUserActivity();
+        }
         mPolicy.userActivity();
     }
 
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 5b9d139..8ce2fd9 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -543,7 +543,8 @@
                 }
 
                 try {
-                    bluetoothOff = bluetooth == null || !bluetooth.isEnabled();
+                    bluetoothOff = bluetooth == null ||
+                            bluetooth.getState() == BluetoothAdapter.STATE_OFF;
                     if (!bluetoothOff) {
                         Log.w(TAG, "Disabling Bluetooth...");
                         bluetooth.disable(false);  // disable but don't persist new state
@@ -577,7 +578,7 @@
 
                     if (!bluetoothOff) {
                         try {
-                            bluetoothOff = !bluetooth.isEnabled();
+                            bluetoothOff = bluetooth.getState() == BluetoothAdapter.STATE_OFF;
                         } catch (RemoteException ex) {
                             Log.e(TAG, "RemoteException during bluetooth shutdown", ex);
                             bluetoothOff = true;
diff --git a/services/core/java/com/android/server/wm/DimLayerController.java b/services/core/java/com/android/server/wm/DimLayerController.java
index 2b9879e..7f97c46 100644
--- a/services/core/java/com/android/server/wm/DimLayerController.java
+++ b/services/core/java/com/android/server/wm/DimLayerController.java
@@ -1,5 +1,6 @@
 package com.android.server.wm;
 
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DIM_LAYER;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -250,6 +251,13 @@
                     duration = getDimLayerFadeDuration(duration);
                 }
                 state.dimLayer.show(dimLayer, dimAmount, duration);
+
+                // If we showed a dim layer, make sure to redo the layout because some things depend
+                // on whether a dim layer is showing or not.
+                if (targetAlpha == 0) {
+                    mDisplayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+                    mDisplayContent.layoutNeeded = true;
+                }
             }
         } else if (state.dimLayer.getLayer() != dimLayer) {
             state.dimLayer.setLayer(dimLayer);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 476a559..107de8b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -42,7 +42,9 @@
 import android.os.SystemProperties;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IMountService;
+import android.provider.Settings;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
@@ -55,6 +57,7 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.accessibility.AccessibilityManagerService;
 import com.android.server.am.ActivityManagerService;
+import com.android.server.am.RetailDemoModeService;
 import com.android.server.audio.AudioService;
 import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
@@ -154,6 +157,8 @@
             "com.google.android.clockwork.ThermalObserver";
     private static final String WEAR_BLUETOOTH_SERVICE_CLASS =
             "com.google.android.clockwork.bluetooth.WearBluetoothService";
+    private static final String WEAR_TIME_SERVICE_CLASS =
+            "com.google.android.clockwork.time.WearTimeService";
     private static final String ACCOUNT_SERVICE_CLASS =
             "com.android.server.accounts.AccountManagerService$Lifecycle";
     private static final String CONTENT_SERVICE_CLASS =
@@ -1160,6 +1165,9 @@
 
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
             mSystemServiceManager.startService(WEAR_BLUETOOTH_SERVICE_CLASS);
+          if (!disableNonCoreServices) {
+              mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
+          }
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -1177,6 +1185,11 @@
         // MMS service broker
         mmsService = mSystemServiceManager.startService(MmsServiceBroker.class);
 
+        if (Settings.Global.getInt(mContentResolver, Settings.Global.DEVICE_PROVISIONED, 0) == 0 ||
+                UserManager.isDeviceInDemoMode(mSystemContext)) {
+            mSystemServiceManager.startService(RetailDemoModeService.class);
+        }
+
         // It is now time to start up the app processes...
 
         Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 0437e1d..59c6970 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -19,7 +19,8 @@
     easymocklib \
     guava \
     android-support-test \
-    mockito-target
+    mockito-target \
+    ShortcutManagerTestUtils
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
new file mode 100644
index 0000000..2f9d06c
--- /dev/null
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="shortcut_title1"></string>
+    <string name="shortcut_text1"></string>
+    <string name="shortcut_disabled_message1"></string>
+    <string name="shortcut_title2"></string>
+    <string name="shortcut_text2"></string>
+    <string name="shortcut_disabled_message2"></string>
+</resources>
diff --git a/services/tests/servicestests/res/xml/shortcut_0.xml b/services/tests/servicestests/res/xml/shortcut_0.xml
new file mode 100644
index 0000000..fda001e
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_0.xml
@@ -0,0 +1,2 @@
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1.xml b/services/tests/servicestests/res/xml/shortcut_1.xml
new file mode 100644
index 0000000..f6d54fc
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_1.xml
@@ -0,0 +1,13 @@
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+        android:shortcutIntentAction="action1"
+        android:shortcutIntentData="data1"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_alt.xml b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
new file mode 100644
index 0000000..bf14f49
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_1_alt.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1-alt"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+        android:shortcutIntentAction="action1"
+        android:shortcutIntentData="data1"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_1_disable.xml b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
new file mode 100644
index 0000000..81a84b4
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_1_disable.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:enabled="false"
+        android:shortcutIcon="@drawable/icon2"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_text2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_2.xml b/services/tests/servicestests/res/xml/shortcut_2.xml
new file mode 100644
index 0000000..96ed382
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_2.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+        android:shortcutIntentAction="action1"
+        android:shortcutIntentData="http://a.b.c/"
+    />
+    <shortcut
+        android:shortcutId="ms2"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon2"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_text2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+        android:shortcutCategories="android.shortcut.conversation"
+        android:shortcutIntentAction="action2"
+        android:shortcutIntentData="http://a.b.c/2"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
new file mode 100644
index 0000000..2f814b7
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_2_duplicate.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="action1"
+    />
+    <shortcut
+        android:shortcutId="ms1"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutIntentAction="action2"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5.xml b/services/tests/servicestests/res/xml/shortcut_5.xml
new file mode 100644
index 0000000..56dba0e
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_5.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+        android:shortcutIntentAction="action1"
+        android:shortcutIntentData="http://a.b.c/1"
+    />
+    <shortcut
+        android:shortcutId="ms2"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon2"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_text2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+        android:shortcutCategories="android.shortcut.conversation"
+        android:shortcutIntentAction="action2"
+    />
+    <shortcut
+        android:shortcutId="ms3"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="ms4"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="ms5"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_5_alt.xml b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
new file mode 100644
index 0000000..74085d9
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_5_alt.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="ms1_alt"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutLongLabel="@string/shortcut_text1"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message1"
+        android:shortcutCategories="android.shortcut.conversation:android.shortcut.media"
+        android:shortcutIntentAction="action1"
+        android:shortcutIntentData="http://a.b.c/1"
+    />
+    <shortcut
+        android:shortcutId="ms2_alt"
+        android:enabled="true"
+        android:shortcutIcon="@drawable/icon2"
+        android:shortcutShortLabel="@string/shortcut_title2"
+        android:shortcutLongLabel="@string/shortcut_text2"
+        android:shortcutDisabledMessage="@string/shortcut_disabled_message2"
+        android:shortcutCategories="android.shortcut.conversation"
+        android:shortcutIntentAction="action2"
+    />
+    <shortcut
+        android:shortcutId="ms3_alt"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="ms4_alt"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="ms5_alt"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_1.xml b/services/tests/servicestests/res/xml/shortcut_error_1.xml
new file mode 100644
index 0000000..5822496
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_error_1.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="x1"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_2.xml b/services/tests/servicestests/res/xml/shortcut_error_2.xml
new file mode 100644
index 0000000..ca67ec7
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_error_2.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="manifest-shortcut-3"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+    <shortcut
+        android:shortcutId="x2"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/res/xml/shortcut_error_3.xml b/services/tests/servicestests/res/xml/shortcut_error_3.xml
new file mode 100644
index 0000000..fb7b31c
--- /dev/null
+++ b/services/tests/servicestests/res/xml/shortcut_error_3.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
+    <shortcut
+        android:shortcutId="manifest-shortcut-3"
+        android:shortcutShortLabel="@string/shortcut_title1"
+    />
+    <shortcut
+        android:shortcutId="x3"
+        android:shortcutShortLabel="@string/shortcut_title1"
+        android:shortcutIntentAction="android.intent.action.VIEW"
+    />
+</shortcuts>
diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
new file mode 100644
index 0000000..808f4dd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProvider.java
@@ -0,0 +1,130 @@
+/*
+ * 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.util;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.test.mock.MockContentProvider;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Fake for system settings.
+ *
+ * To use, ensure that the Context used by the test code returns a ContentResolver that uses this
+ * provider for the Settings authority:
+ *
+ *   class MyTestContext extends MockContext {
+ *       ...
+ *       private final MockContentResolver mContentResolver;
+ *       public MyTestContext(...) {
+ *           ...
+ *           mContentResolver = new MockContentResolver();
+ *           mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+ *       }
+ *       ...
+ *       @Override
+ *       public ContentResolver getContentResolver() {
+ *           return mContentResolver;
+ *       }
+ *
+ * As long as the code under test is using the test Context, the actual code under test does not
+ * need to be modified, and can access Settings using the normal static methods:
+ *
+ *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 0.
+ *   Settings.Global.putInt(cr, "my_setting", 5);
+ *   Settings.Global.getInt(cr, "my_setting", 0);  // Returns 5.
+ *
+ * Note that this class cannot be used in the same process as real settings. This is because it
+ * works by passing an alternate ContentResolver to Settings operations. Unfortunately, the Settings
+ * class only fetches the content provider from the passed-in ContentResolver the first time it's
+ * used, and after that stores it in a per-process static.
+ *
+ * TODO: evaluate implementing settings change notifications. This would require:
+ *
+ * 1. Making ContentResolver#registerContentObserver non-final and overriding it in
+ *    MockContentResolver.
+ * 2. Making FakeSettingsProvider take a ContentResolver argument.
+ * 3. Calling ContentResolver#notifyChange(getUriFor(table, arg), ...) on every settings change.
+ */
+public class FakeSettingsProvider extends MockContentProvider {
+
+    private static final String TAG = FakeSettingsProvider.class.getSimpleName();
+    private static final boolean DBG = false;
+    private static final String[] TABLES = { "system", "secure", "global" };
+
+    private final HashMap<String, HashMap<String, String>> mTables = new HashMap<>();
+
+    public FakeSettingsProvider() {
+        for (int i = 0; i < TABLES.length; i++) {
+            mTables.put(TABLES[i], new HashMap<String, String>());
+        }
+    }
+
+    private Uri getUriFor(String table, String key) {
+        switch (table) {
+            case "system":
+                return Settings.System.getUriFor(key);
+            case "secure":
+                return Settings.Secure.getUriFor(key);
+            case "global":
+                return Settings.Global.getUriFor(key);
+            default:
+                throw new UnsupportedOperationException("Unknown settings table " + table);
+        }
+    }
+
+    public Bundle call(String method, String arg, Bundle extras) {
+        // Methods are "GET_system", "GET_global", "PUT_secure", etc.
+        String[] commands = method.split("_", 2);
+        String op = commands[0];
+        String table = commands[1];
+
+        Bundle out = new Bundle();
+        String value;
+        switch (op) {
+            case "GET":
+                value = mTables.get(table).get(arg);
+                if (value != null) {
+                    if (DBG) {
+                        Log.d(TAG, String.format("Returning fake setting %s.%s = %s",
+                                table, arg, value));
+                    }
+                    out.putString(Settings.NameValueTable.VALUE, value);
+                }
+                break;
+            case "PUT":
+                value = extras.getString(Settings.NameValueTable.VALUE, null);
+                if (DBG) {
+                    Log.d(TAG, String.format("Inserting fake setting %s.%s = %s",
+                            table, arg, value));
+                }
+                if (value != null) {
+                    mTables.get(table).put(arg, value);
+                } else {
+                    mTables.get(table).remove(arg);
+                }
+                break;
+            default:
+                throw new UnsupportedOperationException("Unknown command " + method);
+        }
+
+        return out;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.java
new file mode 100644
index 0000000..a18737c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/internal/util/FakeSettingsProviderTest.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.internal.util;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Unit tests for FakeSettingsProvider.
+ */
+public class FakeSettingsProviderTest extends AndroidTestCase {
+
+    private MockContentResolver mCr;
+
+    @Override
+    public void setUp() throws Exception {
+        mCr = new MockContentResolver();
+        mCr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+    }
+
+    @SmallTest
+    public void testBasicOperation() throws Exception {
+        String settingName = Settings.System.SCREEN_BRIGHTNESS;
+
+        try {
+            Settings.System.getInt(mCr, settingName);
+            fail("FakeSettingsProvider should start off empty.");
+        } catch (Settings.SettingNotFoundException expected) {}
+
+        // Check that fake settings can be written and read back.
+        Settings.System.putInt(mCr, settingName, 123);
+        assertEquals(123, Settings.System.getInt(mCr, settingName));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 4fae4a7..68a35f1 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -26,6 +26,7 @@
 
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
@@ -61,12 +62,15 @@
 import android.os.MessageQueue.IdleHandler;
 import android.os.Process;
 import android.os.SystemClock;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
 
+import com.android.internal.util.FakeSettingsProvider;
 import com.android.internal.util.WakeupMessage;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
@@ -118,27 +122,24 @@
     }
 
     private class MockContext extends BroadcastInterceptingContext {
+        private final MockContentResolver mContentResolver;
+
         MockContext(Context base) {
             super(base);
+            mContentResolver = new MockContentResolver();
+            mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         }
 
         @Override
-        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-            // PendingIntents sent by the AlarmManager are not intercepted by
-            // BroadcastInterceptingContext so we must really register the receiver.
-            // This shouldn't effect the real NetworkMonitors as the action contains a random token.
-            if (filter.getAction(0).startsWith("android.net.netmon.lingerExpired")) {
-                return getBaseContext().registerReceiver(receiver, filter);
-            } else {
-                return super.registerReceiver(receiver, filter);
-            }
-        }
-
-        @Override
-        public Object getSystemService (String name) {
+        public Object getSystemService(String name) {
             if (name == Context.CONNECTIVITY_SERVICE) return mCm;
             return super.getSystemService(name);
         }
+
+        @Override
+        public ContentResolver getContentResolver() {
+            return mContentResolver;
+        }
     }
 
     /**
@@ -641,7 +642,6 @@
         public void waitForIdle() {
             waitForIdle(TIMEOUT_MS);
         }
-
     }
 
     private interface Criteria {
@@ -1477,6 +1477,73 @@
         defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
     }
 
+    @SmallTest
+    public void testMobileDataAlwaysOn() throws Exception {
+        final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+        final NetworkRequest cellRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_CELLULAR).build();
+        mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+
+        final HandlerThread handlerThread = new HandlerThread("MobileDataAlwaysOnFactory");
+        handlerThread.start();
+        NetworkCapabilities filter = new NetworkCapabilities()
+                .addTransportType(TRANSPORT_CELLULAR)
+                .addCapability(NET_CAPABILITY_INTERNET);
+        final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+                mServiceContext, "testFactory", filter);
+        testFactory.setScoreFilter(40);
+
+        // Register the factory and expect it to start looking for a network.
+        testFactory.expectAddRequests(1);
+        testFactory.register();
+        testFactory.waitForNetworkRequests(1);
+        assertTrue(testFactory.getMyStartRequested());
+
+        // Bring up wifi. The factory stops looking for a network.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        testFactory.expectAddRequests(2);  // Because the default request changes score twice.
+        mWiFiNetworkAgent.connect(true);
+        testFactory.waitForNetworkRequests(1);
+        assertFalse(testFactory.getMyStartRequested());
+
+        ContentResolver cr = mServiceContext.getContentResolver();
+
+        // Turn on mobile data always on. The factory starts looking again.
+        testFactory.expectAddRequests(1);
+        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 1);
+        mService.updateMobileDataAlwaysOn();
+        testFactory.waitForNetworkRequests(2);
+        assertTrue(testFactory.getMyStartRequested());
+
+        // Bring up cell data and check that the factory stops looking.
+        assertEquals(1, mCm.getAllNetworks().length);
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        testFactory.expectAddRequests(2);  // Because the cell request changes score twice.
+        mCellNetworkAgent.connect(true);
+        cellNetworkCallback.expectCallback(CallbackState.AVAILABLE);
+        testFactory.waitForNetworkRequests(2);
+        assertFalse(testFactory.getMyStartRequested());  // Because the cell network outscores us.
+
+        // Check that cell data stays up.
+        mService.waitForIdle();
+        verifyActiveNetwork(TRANSPORT_WIFI);
+        assertEquals(2, mCm.getAllNetworks().length);
+
+        // Turn off mobile data always on and expect the request to disappear...
+        testFactory.expectRemoveRequests(1);
+        Settings.Global.putInt(cr, Settings.Global.MOBILE_DATA_ALWAYS_ON, 0);
+        mService.updateMobileDataAlwaysOn();
+        testFactory.waitForNetworkRequests(1);
+
+        // ...  and cell data to be torn down.
+        cellNetworkCallback.expectCallback(CallbackState.LOST);
+        assertEquals(1, mCm.getAllNetworks().length);
+
+        testFactory.unregister();
+        mCm.unregisterNetworkCallback(cellNetworkCallback);
+        handlerThread.quit();
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
new file mode 100644
index 0000000..ed53b77
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -0,0 +1,1484 @@
+/*
+ * 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.pm;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.cloneShortcutList;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.UserIdInt;
+import android.app.Activity;
+import android.app.IUidObserver;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ILauncherApps;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.content.pm.ShortcutServiceInternal;
+import android.content.pm.Signature;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.InstrumentationTestCase;
+import android.test.mock.MockContext;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.pm.LauncherAppsService.LauncherAppsImpl;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+
+import org.junit.Assert;
+import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
+    protected static final String TAG = "ShortcutManagerTest";
+
+    /**
+     * Whether to enable dump or not.  Should be only true when debugging to avoid bugs where
+     * dump affecting the behavior.
+     */
+    protected static final boolean ENABLE_DUMP = false; // DO NOT SUBMIT WITH true
+
+    protected static final boolean DUMP_IN_TEARDOWN = false; // DO NOT SUBMIT WITH true
+
+    protected static final String[] EMPTY_STRINGS = new String[0]; // Just for readability.
+
+    // public for mockito
+    public class BaseContext extends MockContext {
+        @Override
+        public Object getSystemService(String name) {
+            switch (name) {
+                case Context.USER_SERVICE:
+                    return mMockUserManager;
+            }
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getSystemServiceName(Class<?> serviceClass) {
+            return getTestContext().getSystemServiceName(serviceClass);
+        }
+
+        @Override
+        public PackageManager getPackageManager() {
+            return mMockPackageManager;
+        }
+
+        @Override
+        public Resources getResources() {
+            return getTestContext().getResources();
+        }
+
+        @Override
+        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
+                IntentFilter filter, String broadcastPermission, Handler scheduler) {
+            // ignore.
+            return null;
+        }
+    }
+
+    /** Context used in the client side */
+    public class ClientContext extends BaseContext {
+        @Override
+        public String getPackageName() {
+            return mInjectedClientPackage;
+        }
+
+        @Override
+        public int getUserId() {
+            return getCallingUserId();
+        }
+    }
+
+    /** Context used in the service side */
+    public class ServiceContext extends BaseContext {
+        long injectClearCallingIdentity() {
+            final int prevCallingUid = mInjectedCallingUid;
+            mInjectedCallingUid = Process.SYSTEM_UID;
+            return prevCallingUid;
+        }
+
+        void injectRestoreCallingIdentity(long token) {
+            mInjectedCallingUid = (int) token;
+        }
+
+        @Override
+        public void startActivityAsUser(@RequiresPermission Intent intent, @Nullable Bundle options,
+                UserHandle userId) {
+        }
+
+        @Override
+        public int getUserId() {
+            return UserHandle.USER_SYSTEM;
+        }
+
+        public PackageInfo injectGetActivitiesWithMetadata(
+                String packageName, @UserIdInt int userId) {
+            return BaseShortcutManagerTest.this.injectGetActivitiesWithMetadata(packageName, userId);
+        }
+
+        public XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
+            return BaseShortcutManagerTest.this.injectXmlMetaData(activityInfo, key);
+        }
+    }
+
+    /** ShortcutService with injection override methods. */
+    protected final class ShortcutServiceTestable extends ShortcutService {
+        final ServiceContext mContext;
+        IUidObserver mUidObserver;
+
+        public ShortcutServiceTestable(ServiceContext context, Looper looper) {
+            super(context, looper);
+            mContext = context;
+        }
+
+        @Override
+        boolean injectShouldPerformVerification() {
+            return true; // Always verify during unit tests.
+        }
+
+        @Override
+        String injectShortcutManagerConstants() {
+            return ConfigConstants.KEY_RESET_INTERVAL_SEC + "=" + (INTERVAL / 1000) + ","
+                    + ConfigConstants.KEY_MAX_SHORTCUTS + "=" + MAX_SHORTCUTS + ","
+                    + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "="
+                    + MAX_UPDATES_PER_INTERVAL + ","
+                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=" + MAX_ICON_DIMENSION + ","
+                    + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "="
+                    + MAX_ICON_DIMENSION_LOWRAM + ","
+                    + ConfigConstants.KEY_ICON_FORMAT + "=PNG,"
+                    + ConfigConstants.KEY_ICON_QUALITY + "=100";
+        }
+
+        @Override
+        long injectClearCallingIdentity() {
+            return mContext.injectClearCallingIdentity();
+        }
+
+        @Override
+        void injectRestoreCallingIdentity(long token) {
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        int injectDipToPixel(int dip) {
+            return dip;
+        }
+
+        @Override
+        long injectCurrentTimeMillis() {
+            return mInjectedCurrentTimeMillis;
+        }
+
+        @Override
+        long injectElapsedRealtime() {
+            // TODO This should be kept separately from mInjectedCurrentTimeMillis, since
+            // this should increase even if we rewind mInjectedCurrentTimeMillis in some tests.
+            return mInjectedCurrentTimeMillis - START_TIME;
+        }
+
+        @Override
+        int injectBinderCallingUid() {
+            return mInjectedCallingUid;
+        }
+
+        @Override
+        int injectGetPackageUid(String packageName, int userId) {
+            return getInjectedPackageInfo(packageName, userId, false).applicationInfo.uid;
+        }
+
+        @Override
+        File injectSystemDataPath() {
+            return new File(mInjectedFilePathRoot, "system");
+        }
+
+        @Override
+        File injectUserDataPath(@UserIdInt int userId) {
+            return new File(mInjectedFilePathRoot, "user-" + userId);
+        }
+
+        @Override
+        void injectValidateIconResPackage(ShortcutInfo shortcut, Icon icon) {
+            // Can't check
+        }
+
+        @Override
+        boolean injectIsLowRamDevice() {
+            return mInjectedIsLowRamDevice;
+        }
+
+        @Override
+        void injectRegisterUidObserver(IUidObserver observer, int which) {
+            mUidObserver = observer;
+        }
+
+        @Override
+        PackageManagerInternal injectPackageManagerInternal() {
+            return mMockPackageManagerInternal;
+        }
+
+        @Override
+        boolean hasShortcutHostPermission(@NonNull String callingPackage, int userId) {
+            return mDefaultLauncherChecker.test(callingPackage, userId);
+        }
+
+        @Override
+        PackageInfo injectPackageInfo(String packageName, @UserIdInt int userId,
+                boolean getSignatures) {
+            return getInjectedPackageInfo(packageName, userId, getSignatures);
+        }
+
+        @Override
+        ApplicationInfo injectApplicationInfo(String packageName, @UserIdInt int userId) {
+            PackageInfo pi = injectPackageInfo(packageName, userId, /* getSignatures= */ false);
+            return pi != null ? pi.applicationInfo : null;
+        }
+
+        @Override
+        List<ApplicationInfo> injectInstalledApplications(@UserIdInt int userId) {
+            return getInstalledApplications(userId);
+        }
+
+        @Override
+        PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
+            return mContext.injectGetActivitiesWithMetadata(packageName, userId);
+        }
+
+        @Override
+        XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
+            return mContext.injectXmlMetaData(activityInfo, key);
+        }
+
+        @Override
+        void postToHandler(Runnable r) {
+            final long token = mContext.injectClearCallingIdentity();
+            r.run();
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        void injectEnforceCallingPermission(String permission, String message) {
+            if (!mCallerPermissions.contains(permission)) {
+                throw new SecurityException("Missing permission: " + permission);
+            }
+        }
+
+        @Override
+        void wtf(String message, Exception e) {
+            // During tests, WTF is fatal.
+            fail(message + "  exception: " + e);
+        }
+    }
+
+    /** ShortcutManager with injection override methods. */
+    protected class ShortcutManagerTestable extends ShortcutManager {
+        public ShortcutManagerTestable(Context context, ShortcutServiceTestable service) {
+            super(context, service);
+        }
+
+        @Override
+        protected int injectMyUserId() {
+            return UserHandle.getUserId(mInjectedCallingUid);
+        }
+
+        @Override
+        public boolean setDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+            // Note to simulate the binder RPC, we need to clone the incoming arguments.
+            // Otherwise bad things will happen because they're mutable.
+            return super.setDynamicShortcuts(cloneShortcutList(shortcutInfoList));
+        }
+
+        @Override
+        public boolean addDynamicShortcuts(@NonNull List<ShortcutInfo> shortcutInfoList) {
+            // Note to simulate the binder RPC, we need to clone the incoming arguments.
+            return super.addDynamicShortcuts(cloneShortcutList(shortcutInfoList));
+        }
+
+        @Override
+        public boolean updateShortcuts(List<ShortcutInfo> shortcutInfoList) {
+            // Note to simulate the binder RPC, we need to clone the incoming arguments.
+            return super.updateShortcuts(cloneShortcutList(shortcutInfoList));
+        }
+    }
+
+    protected class LauncherAppImplTestable extends LauncherAppsImpl {
+        final ServiceContext mContext;
+
+        public LauncherAppImplTestable(ServiceContext context) {
+            super(context);
+            mContext = context;
+        }
+
+        @Override
+        public void verifyCallingPackage(String callingPackage) {
+            // SKIP
+        }
+
+        @Override
+        void postToPackageMonitorHandler(Runnable r) {
+            final long token = mContext.injectClearCallingIdentity();
+            r.run();
+            mContext.injectRestoreCallingIdentity(token);
+        }
+
+        @Override
+        int injectBinderCallingUid() {
+            return mInjectedCallingUid;
+        }
+
+        @Override
+        long injectClearCallingIdentity() {
+            final int prevCallingUid = mInjectedCallingUid;
+            mInjectedCallingUid = Process.SYSTEM_UID;
+            return prevCallingUid;
+        }
+
+        @Override
+        void injectRestoreCallingIdentity(long token) {
+            mInjectedCallingUid = (int) token;
+        }
+    }
+
+    protected class LauncherAppsTestable extends LauncherApps {
+        public LauncherAppsTestable(Context context, ILauncherApps service) {
+            super(context, service);
+        }
+    }
+
+    public static class ShortcutActivity extends Activity {
+    }
+
+    public static class ShortcutActivity2 extends Activity {
+    }
+
+    public static class ShortcutActivity3 extends Activity {
+    }
+
+    protected ServiceContext mServiceContext;
+    protected ClientContext mClientContext;
+
+    protected ShortcutServiceTestable mService;
+    protected ShortcutManagerTestable mManager;
+    protected ShortcutServiceInternal mInternal;
+
+    protected LauncherAppImplTestable mLauncherAppImpl;
+
+    // LauncherApps has per-instace state, so we need a differnt instance for each launcher.
+    protected final Map<Pair<Integer, String>, LauncherAppsTestable>
+            mLauncherAppsMap = new HashMap<>();
+    protected LauncherAppsTestable mLauncherApps; // Current one
+
+    protected File mInjectedFilePathRoot;
+
+    protected long mInjectedCurrentTimeMillis;
+
+    protected boolean mInjectedIsLowRamDevice;
+
+    protected int mInjectedCallingUid;
+    protected String mInjectedClientPackage;
+
+    protected Map<String, PackageInfo> mInjectedPackages;
+
+    protected Set<PackageWithUser> mUninstalledPackages;
+
+    protected PackageManager mMockPackageManager;
+    protected PackageManagerInternal mMockPackageManagerInternal;
+    protected UserManager mMockUserManager;
+    protected UsageStatsManagerInternal mMockUsageStatsManagerInternal;
+
+    protected static final String CALLING_PACKAGE_1 = "com.android.test.1";
+    protected static final int CALLING_UID_1 = 10001;
+
+    protected static final String CALLING_PACKAGE_2 = "com.android.test.2";
+    protected static final int CALLING_UID_2 = 10002;
+
+    protected static final String CALLING_PACKAGE_3 = "com.android.test.3";
+    protected static final int CALLING_UID_3 = 10003;
+
+    protected static final String CALLING_PACKAGE_4 = "com.android.test.4";
+    protected static final int CALLING_UID_4 = 10004;
+
+    protected static final String LAUNCHER_1 = "com.android.launcher.1";
+    protected static final int LAUNCHER_UID_1 = 10011;
+
+    protected static final String LAUNCHER_2 = "com.android.launcher.2";
+    protected static final int LAUNCHER_UID_2 = 10012;
+
+    protected static final String LAUNCHER_3 = "com.android.launcher.3";
+    protected static final int LAUNCHER_UID_3 = 10013;
+
+    protected static final String LAUNCHER_4 = "com.android.launcher.4";
+    protected static final int LAUNCHER_UID_4 = 10014;
+
+    protected static final int USER_0 = UserHandle.USER_SYSTEM;
+    protected static final int USER_10 = 10;
+    protected static final int USER_11 = 11;
+    protected static final int USER_P0 = 20; // profile of user 0
+
+    protected static final UserHandle HANDLE_USER_0 = UserHandle.of(USER_0);
+    protected static final UserHandle HANDLE_USER_10 = UserHandle.of(USER_10);
+    protected static final UserHandle HANDLE_USER_11 = UserHandle.of(USER_11);
+    protected static final UserHandle HANDLE_USER_P0 = UserHandle.of(USER_P0);
+
+    protected static final UserInfo USER_INFO_0 = withProfileGroupId(
+            new UserInfo(USER_0, "user0",
+                    UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED), 10);
+
+    protected static final UserInfo USER_INFO_10 =
+            new UserInfo(USER_10, "user10", UserInfo.FLAG_INITIALIZED);
+
+    protected static final UserInfo USER_INFO_11 =
+            new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
+
+    protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
+            new UserInfo(USER_P0, "userP0",
+                    UserInfo.FLAG_MANAGED_PROFILE), 10);
+
+    protected BiPredicate<String, Integer> mDefaultLauncherChecker =
+            (callingPackage, userId) ->
+            LAUNCHER_1.equals(callingPackage) || LAUNCHER_2.equals(callingPackage)
+            || LAUNCHER_3.equals(callingPackage) || LAUNCHER_4.equals(callingPackage);
+
+    protected static final long START_TIME = 1440000000101L;
+
+    protected static final long INTERVAL = 10000;
+
+    protected static final int MAX_SHORTCUTS = 10;
+
+    protected static final int MAX_UPDATES_PER_INTERVAL = 3;
+
+    protected static final int MAX_ICON_DIMENSION = 128;
+
+    protected static final int MAX_ICON_DIMENSION_LOWRAM = 32;
+
+    protected static final ShortcutQuery QUERY_ALL = new ShortcutQuery();
+
+    protected final ArrayList<String> mCallerPermissions = new ArrayList<>();
+
+    protected final HashMap<String, LinkedHashMap<ComponentName, Integer>> mActivityMetadataResId
+            = new HashMap<>();
+
+    static {
+        QUERY_ALL.setQueryFlags(
+                ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mServiceContext = spy(new ServiceContext());
+        mClientContext = new ClientContext();
+
+        mMockPackageManager = mock(PackageManager.class);
+        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+        mMockUserManager = mock(UserManager.class);
+        mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class);
+
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mMockPackageManagerInternal);
+        LocalServices.removeServiceForTest(UsageStatsManagerInternal.class);
+        LocalServices.addService(UsageStatsManagerInternal.class, mMockUsageStatsManagerInternal);
+
+        // Prepare injection values.
+
+        mInjectedCurrentTimeMillis = START_TIME;
+
+        mInjectedPackages = new HashMap<>();
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1);
+        addPackage(CALLING_PACKAGE_2, CALLING_UID_2, 2);
+        addPackage(CALLING_PACKAGE_3, CALLING_UID_3, 3);
+        addPackage(CALLING_PACKAGE_4, CALLING_UID_4, 10);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4);
+        addPackage(LAUNCHER_2, LAUNCHER_UID_2, 5);
+        addPackage(LAUNCHER_3, LAUNCHER_UID_3, 6);
+        addPackage(LAUNCHER_4, LAUNCHER_UID_4, 10);
+
+        // CALLING_PACKAGE_3 / LAUNCHER_3 are not backup target.
+        updatePackageInfo(CALLING_PACKAGE_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+        updatePackageInfo(LAUNCHER_3,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        mUninstalledPackages = new HashSet<>();
+
+        mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
+
+        deleteAllSavedFiles();
+
+        // Set up users.
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_0));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_10;
+        }).when(mMockUserManager).getUserInfo(eq(USER_10));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_11;
+        }).when(mMockUserManager).getUserInfo(eq(USER_11));
+
+        doAnswer(inv -> {
+                assertSystem();
+                return USER_INFO_P0;
+        }).when(mMockUserManager).getUserInfo(eq(USER_P0));
+
+        // User 0 is always running.
+        when(mMockUserManager.isUserRunning(eq(USER_0))).thenAnswer(new AnswerIsUserRunning(true));
+
+        initService();
+        setCaller(CALLING_PACKAGE_1);
+
+        // In order to complicate the situation, we set mLocaleChangeSequenceNumber to 1 by
+        // calling this.  Running test with mLocaleChangeSequenceNumber == 0 might make us miss
+        // some edge cases.
+        mInternal.onSystemLocaleChangedNoLock();
+    }
+
+    /**
+     * Returns a boolean but also checks if the current UID is SYSTEM_UID.
+     */
+    protected class AnswerIsUserRunning implements Answer<Boolean> {
+        protected final boolean mAnswer;
+
+        protected AnswerIsUserRunning(boolean answer) {
+            mAnswer = answer;
+        }
+
+        @Override
+        public Boolean answer(InvocationOnMock invocation) throws Throwable {
+            assertEquals("isUserRunning() must be called on SYSTEM UID.",
+                    Process.SYSTEM_UID, mInjectedCallingUid);
+            return mAnswer;
+        }
+    }
+
+    protected static UserInfo withProfileGroupId(UserInfo in, int groupId) {
+        in.profileGroupId = groupId;
+        return in;
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        if (DUMP_IN_TEARDOWN) dumpsysOnLogcat("Teardown");
+
+        shutdownServices();
+
+        super.tearDown();
+    }
+
+    protected Context getTestContext() {
+        return getInstrumentation().getContext();
+    }
+
+    protected void deleteAllSavedFiles() {
+        // Empty the data directory.
+        if (mInjectedFilePathRoot.exists()) {
+            Assert.assertTrue("failed to delete dir",
+                    FileUtils.deleteContents(mInjectedFilePathRoot));
+        }
+        mInjectedFilePathRoot.mkdirs();
+    }
+
+    /** (Re-) init the manager and the service. */
+    protected void initService() {
+        shutdownServices();
+
+        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+        // Instantiate targets.
+        mService = new ShortcutServiceTestable(mServiceContext, Looper.getMainLooper());
+        mManager = new ShortcutManagerTestable(mClientContext, mService);
+
+        mInternal = LocalServices.getService(ShortcutServiceInternal.class);
+
+        mLauncherAppImpl = new LauncherAppImplTestable(mServiceContext);
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
+
+        // Load the setting file.
+        mService.onBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
+    }
+
+    protected void shutdownServices() {
+        if (mService != null) {
+            // Flush all the unsaved data from the previous instance.
+            mService.saveDirtyInfo();
+        }
+        LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
+
+        mService = null;
+        mManager = null;
+        mInternal = null;
+        mLauncherAppImpl = null;
+        mLauncherApps = null;
+        mLauncherAppsMap.clear();
+    }
+
+    protected void addPackage(String packageName, int uid, int version) {
+        addPackage(packageName, uid, version, packageName);
+    }
+
+    protected Signature[] genSignatures(String... signatures) {
+        final Signature[] sigs = new Signature[signatures.length];
+        for (int i = 0; i < signatures.length; i++){
+            sigs[i] = new Signature(signatures[i].getBytes());
+        }
+        return sigs;
+    }
+
+    protected PackageInfo genPackage(String packageName, int uid, int version, String... signatures) {
+        final PackageInfo pi = new PackageInfo();
+        pi.packageName = packageName;
+        pi.applicationInfo = new ApplicationInfo();
+        pi.applicationInfo.uid = uid;
+        pi.applicationInfo.flags = ApplicationInfo.FLAG_INSTALLED
+                | ApplicationInfo.FLAG_ALLOW_BACKUP;
+        pi.versionCode = version;
+        pi.applicationInfo.versionCode = version;
+        pi.signatures = genSignatures(signatures);
+
+        return pi;
+    }
+
+    protected void addPackage(String packageName, int uid, int version, String... signatures) {
+        mInjectedPackages.put(packageName, genPackage(packageName, uid, version, signatures));
+    }
+
+    protected void updatePackageInfo(String packageName, Consumer<PackageInfo> c) {
+        c.accept(mInjectedPackages.get(packageName));
+    }
+
+    protected void updatePackageVersion(String packageName, int increment) {
+        updatePackageInfo(packageName, pi -> {
+            pi.versionCode += increment;
+            pi.applicationInfo.versionCode += increment;
+        });
+    }
+
+    protected void updatePackageLastUpdateTime(String packageName, long increment) {
+        updatePackageInfo(packageName, pi -> {
+            pi.lastUpdateTime += increment;
+        });
+    }
+
+    protected void uninstallPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.v(TAG, "Unnstall package " + packageName + " / " + userId);
+        }
+        mUninstalledPackages.add(PackageWithUser.of(userId, packageName));
+    }
+
+    protected void installPackage(int userId, String packageName) {
+        if (ENABLE_DUMP) {
+            Log.v(TAG, "Install package " + packageName + " / " + userId);
+        }
+        mUninstalledPackages.remove(PackageWithUser.of(userId, packageName));
+    }
+
+    PackageInfo getInjectedPackageInfo(String packageName, @UserIdInt int userId,
+            boolean getSignatures) {
+        final PackageInfo pi = mInjectedPackages.get(packageName);
+        if (pi == null) return null;
+
+        final PackageInfo ret = new PackageInfo();
+        ret.packageName = pi.packageName;
+        ret.versionCode = pi.versionCode;
+        ret.lastUpdateTime = pi.lastUpdateTime;
+
+        ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
+        ret.applicationInfo.uid = UserHandle.getUid(userId, pi.applicationInfo.uid);
+        ret.applicationInfo.packageName = pi.packageName;
+
+        if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
+            ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
+        }
+
+        if (getSignatures) {
+            ret.signatures = pi.signatures;
+        }
+
+        return ret;
+    }
+
+    protected void addApplicationInfo(PackageInfo pi, List<ApplicationInfo> list) {
+        if (pi != null && pi.applicationInfo != null) {
+            list.add(pi.applicationInfo);
+        }
+    }
+
+    protected List<ApplicationInfo> getInstalledApplications(int userId) {
+        final ArrayList<ApplicationInfo> ret = new ArrayList<>();
+
+        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_1, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_2, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_3, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(CALLING_PACKAGE_4, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_1, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_2, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_3, userId, false), ret);
+        addApplicationInfo(getInjectedPackageInfo(LAUNCHER_4, userId, false), ret);
+
+        return ret;
+    }
+
+    protected void addManifestShortcutResource(ComponentName activity, int resId) {
+        final String packageName = activity.getPackageName();
+        LinkedHashMap<ComponentName, Integer> map = mActivityMetadataResId.get(packageName);
+        if (map == null) {
+            map = new LinkedHashMap<>();
+            mActivityMetadataResId.put(packageName, map);
+        }
+        map.put(activity, resId);
+    }
+
+    protected PackageInfo injectGetActivitiesWithMetadata(String packageName, @UserIdInt int userId) {
+        final PackageInfo ret = getInjectedPackageInfo(packageName, userId,
+                /* getSignatures=*/ false);
+
+        final HashMap<ComponentName, Integer> activities = mActivityMetadataResId.get(packageName);
+        if (activities != null) {
+            final ArrayList<ActivityInfo> list = new ArrayList<>();
+
+            for (ComponentName cn : activities.keySet()) {
+                ActivityInfo ai = new ActivityInfo();
+                ai.packageName = cn.getPackageName();
+                ai.name = cn.getClassName();
+                ai.metaData = new Bundle();
+                ai.metaData.putInt(ShortcutParser.METADATA_KEY, activities.get(cn));
+                list.add(ai);
+            }
+            ret.activities = list.toArray(new ActivityInfo[list.size()]);
+        }
+        return ret;
+    }
+
+    protected XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
+        if (!ShortcutParser.METADATA_KEY.equals(key) || activityInfo.metaData == null) {
+            return null;
+        }
+        final int resId = activityInfo.metaData.getInt(key);
+        return getTestContext().getResources().getXml(resId);
+    }
+
+    /** Replace the current calling package */
+    protected void setCaller(String packageName, int userId) {
+        mInjectedClientPackage = packageName;
+        mInjectedCallingUid =
+                Preconditions.checkNotNull(getInjectedPackageInfo(packageName, userId, false),
+                        "Unknown package").applicationInfo.uid;
+
+        // Set up LauncherApps for this caller.
+        final Pair<Integer, String> key = Pair.create(userId, packageName);
+        if (!mLauncherAppsMap.containsKey(key)) {
+            mLauncherAppsMap.put(key, new LauncherAppsTestable(mClientContext, mLauncherAppImpl));
+        }
+        mLauncherApps = mLauncherAppsMap.get(key);
+    }
+
+    protected void setCaller(String packageName) {
+        setCaller(packageName, UserHandle.USER_SYSTEM);
+    }
+
+    protected String getCallingPackage() {
+        return mInjectedClientPackage;
+    }
+
+    protected void setDefaultLauncherChecker(BiPredicate<String, Integer> p) {
+        mDefaultLauncherChecker = p;
+    }
+
+    protected void runWithCaller(String packageName, int userId, Runnable r) {
+        final String previousPackage = mInjectedClientPackage;
+        final int previousUserId = UserHandle.getUserId(mInjectedCallingUid);
+
+        setCaller(packageName, userId);
+
+        r.run();
+
+        setCaller(previousPackage, previousUserId);
+    }
+
+    protected int getCallingUserId() {
+        return UserHandle.getUserId(mInjectedCallingUid);
+    }
+
+    protected UserHandle getCallingUser() {
+        return UserHandle.of(getCallingUserId());
+    }
+
+    /** For debugging */
+    protected void dumpsysOnLogcat() {
+        dumpsysOnLogcat("");
+    }
+
+    protected void dumpsysOnLogcat(String message) {
+        dumpsysOnLogcat(message, false);
+    }
+
+    protected void dumpsysOnLogcat(String message, boolean force) {
+        if (force || !ENABLE_DUMP) return;
+
+        final ByteArrayOutputStream out = new ByteArrayOutputStream();
+        final PrintWriter pw = new PrintWriter(out);
+        mService.dumpInner(pw, null);
+        pw.close();
+
+        Log.v(TAG, "Dumping ShortcutService: " + message);
+        for (String line : out.toString().split("\n")) {
+            Log.v(TAG, line);
+        }
+    }
+
+    /**
+     * For debugging, dump arbitrary file on logcat.
+     */
+    protected void dumpFileOnLogcat(String path) {
+        dumpFileOnLogcat(path, "");
+    }
+
+    protected void dumpFileOnLogcat(String path, String message) {
+        if (!ENABLE_DUMP) return;
+
+        Log.v(TAG, "Dumping file: " + path + " " + message);
+        final StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(new FileReader(path))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                Log.v(TAG, line);
+            }
+        } catch (Exception e) {
+            Log.e(TAG, "Couldn't read file", e);
+            fail("Exception " + e);
+        }
+    }
+
+    /**
+     * For debugging, dump the main state file on logcat.
+     */
+    protected void dumpBaseStateFile() {
+        mService.saveDirtyInfo();
+        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+                + "/system/" + ShortcutService.FILENAME_BASE_STATE);
+    }
+
+    /**
+     * For debugging, dump per-user state file on logcat.
+     */
+    protected void dumpUserFile(int userId) {
+        dumpUserFile(userId, "");
+    }
+
+    protected void dumpUserFile(int userId, String message) {
+        mService.saveDirtyInfo();
+        dumpFileOnLogcat(mInjectedFilePathRoot.getAbsolutePath()
+                + "/user-" + userId
+                + "/" + ShortcutService.FILENAME_USER_PACKAGES, message);
+    }
+
+    protected void waitOnMainThread() throws Throwable {
+        runTestOnUiThread(() -> {});
+    }
+
+    /**
+     * Make a shortcut with an ID.
+     */
+    protected ShortcutInfo makeShortcut(String id) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
+    protected ShortcutInfo makeShortcutWithTitle(String id, String title) {
+        return makeShortcut(
+                id, title, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
+    /**
+     * Make a shortcut with an ID and timestamp.
+     */
+    protected ShortcutInfo makeShortcutWithTimestamp(String id, long timestamp) {
+        final ShortcutInfo s = makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+        s.setTimestamp(timestamp);
+        return s;
+    }
+
+    /**
+     * Make a shortcut with an ID, a timestamp and an activity component
+     */
+    protected ShortcutInfo makeShortcutWithTimestampWithActivity(String id, long timestamp,
+            ComponentName activity) {
+        final ShortcutInfo s = makeShortcut(
+                id, "Title-" + id, activity, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+        s.setTimestamp(timestamp);
+        return s;
+    }
+
+    /**
+     * Make a shortcut with an ID and icon.
+     */
+    protected ShortcutInfo makeShortcutWithIcon(String id, Icon icon) {
+        return makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, icon,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
+    protected ShortcutInfo makePackageShortcut(String packageName, String id) {
+        String origCaller = getCallingPackage();
+
+        setCaller(packageName);
+        ShortcutInfo s = makeShortcut(
+                id, "Title-" + id, /* activity =*/ null, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+        setCaller(origCaller); // restore the caller
+
+        return s;
+    }
+
+    /**
+     * Make multiple shortcuts with IDs.
+     */
+    protected List<ShortcutInfo> makeShortcuts(String... ids) {
+        final ArrayList<ShortcutInfo> ret = new ArrayList();
+        for (String id : ids) {
+            ret.add(makeShortcut(id));
+        }
+        return ret;
+    }
+
+    protected ShortcutInfo.Builder makeShortcutBuilder() {
+        return new ShortcutInfo.Builder(mClientContext);
+    }
+
+    protected ShortcutInfo makeShortcutWithActivity(String id, ComponentName activity) {
+        return makeShortcut(
+                id, "Title-" + id, activity, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
+    protected ShortcutInfo makeShortcutWithActivityAndTitle(String id, ComponentName activity,
+            String title) {
+        return makeShortcut(
+                id, title, activity, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), /* rank =*/ 0);
+    }
+
+    protected ShortcutInfo makeShortcutWithActivityAndRank(String id, ComponentName activity,
+            int rank) {
+        return makeShortcut(
+                id, "Title-" + id, activity, /* icon =*/ null,
+                makeIntent(Intent.ACTION_VIEW, ShortcutActivity.class), rank);
+    }
+
+    /**
+     * Make a shortcut with details.
+     */
+    protected ShortcutInfo makeShortcut(String id, String title, ComponentName activity,
+            Icon icon, Intent intent, int rank) {
+        final ShortcutInfo.Builder  b = new ShortcutInfo.Builder(mClientContext)
+                .setId(id)
+                .setActivity(new ComponentName(mClientContext.getPackageName(), "dummy"))
+                .setTitle(title)
+                .setRank(rank)
+                .setIntent(intent);
+        if (icon != null) {
+            b.setIcon(icon);
+        }
+        if (activity != null) {
+            b.setActivity(activity);
+        }
+        final ShortcutInfo s = b.build();
+
+        s.setTimestamp(mInjectedCurrentTimeMillis); // HACK
+
+        return s;
+    }
+
+    /**
+     * Make an intent.
+     */
+    protected Intent makeIntent(String action, Class<?> clazz, Object... bundleKeysAndValues) {
+        final Intent intent = new Intent(action);
+        intent.setComponent(makeComponent(clazz));
+        intent.replaceExtras(makeBundle(bundleKeysAndValues));
+        return intent;
+    }
+
+    /**
+     * Make an component name, with the client context.
+     */
+    @NonNull
+    protected ComponentName makeComponent(Class<?> clazz) {
+        return new ComponentName(mClientContext, clazz);
+    }
+
+    @NonNull
+    protected ShortcutInfo findById(List<ShortcutInfo> list, String id) {
+        for (ShortcutInfo s : list) {
+            if (s.getId().equals(id)) {
+                return s;
+            }
+        }
+        fail("Shortcut with id " + id + " not found");
+        return null;
+    }
+
+    protected void assertSystem() {
+        assertEquals("Caller must be system", Process.SYSTEM_UID, mInjectedCallingUid);
+    }
+
+    protected void assertResetTimes(long expectedLastResetTime, long expectedNextResetTime) {
+        assertEquals(expectedLastResetTime, mService.getLastResetTimeLocked());
+        assertEquals(expectedNextResetTime, mService.getNextResetTimeLocked());
+    }
+
+    public static List<ShortcutInfo> assertAllNotHaveIcon(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getIcon());
+        }
+        return actualShortcuts;
+    }
+
+    @NonNull
+    protected List<ShortcutInfo> assertAllHaveFlags(@NonNull List<ShortcutInfo> actualShortcuts,
+            int shortcutFlags) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " doesn't have flags " + shortcutFlags,
+                    s.hasFlags(shortcutFlags));
+        }
+        return actualShortcuts;
+    }
+
+    protected ShortcutInfo getPackageShortcut(String packageName, String shortcutId, int userId) {
+        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
+    }
+
+    protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
+        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
+    }
+
+    protected void assertShortcutNotExists(String packageName, String shortcutId, int userId) {
+        assertTrue(getPackageShortcut(packageName, shortcutId, userId) == null);
+    }
+
+    protected Intent launchShortcutAndGetIntent(
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        reset(mServiceContext);
+        assertTrue(mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                UserHandle.of(userId)));
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mServiceContext).startActivityAsUser(
+                intentCaptor.capture(),
+                any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        return intentCaptor.getValue();
+    }
+
+    protected Intent launchShortcutAndGetIntent_withShortcutInfo(
+            @NonNull String packageName, @NonNull String shortcutId, int userId) {
+        reset(mServiceContext);
+
+        assertTrue(mLauncherApps.startShortcut(
+                getShortcutInfoAsLauncher(packageName, shortcutId, userId), null, null));
+
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mServiceContext).startActivityAsUser(
+                intentCaptor.capture(),
+                any(Bundle.class),
+                eq(UserHandle.of(userId)));
+        return intentCaptor.getValue();
+    }
+
+    protected void assertShortcutLaunchable(@NonNull String packageName, @NonNull String shortcutId,
+            int userId) {
+        assertNotNull(launchShortcutAndGetIntent(packageName, shortcutId, userId));
+        assertNotNull(launchShortcutAndGetIntent_withShortcutInfo(packageName, shortcutId, userId));
+    }
+
+    protected void assertShortcutNotLaunchable(@NonNull String packageName,
+            @NonNull String shortcutId, int userId) {
+        try {
+            final boolean ok = mLauncherApps.startShortcut(packageName, shortcutId, null, null,
+                    UserHandle.of(userId));
+            if (!ok) {
+                return; // didn't launch, okay.
+            }
+            fail();
+        } catch (SecurityException expected) {
+            // security exception is okay too.
+        }
+    }
+
+    protected void assertBitmapDirectories(int userId, String... expectedDirectories) {
+        final Set<String> expected = hashSet(set(expectedDirectories));
+
+        final Set<String> actual = new HashSet<>();
+
+        final File[] files = mService.getUserBitmapFilePath(userId).listFiles();
+        if (files != null) {
+            for (File child : files) {
+                if (child.isDirectory()) {
+                    actual.add(child.getName());
+                }
+            }
+        }
+
+        assertEquals(expected, actual);
+    }
+
+    protected void assertBitmapFiles(int userId, String packageName, String... expectedFiles) {
+        final Set<String> expected = hashSet(set(expectedFiles));
+
+        final Set<String> actual = new HashSet<>();
+
+        final File[] files = new File(mService.getUserBitmapFilePath(userId), packageName)
+                .listFiles();
+        if (files != null) {
+            for (File child : files) {
+                if (child.isFile()) {
+                    actual.add(child.getName());
+                }
+            }
+        }
+
+        assertEquals(expected, actual);
+    }
+
+    protected String getBitmapFilename(int userId, String packageName, String shortcutId) {
+        final ShortcutInfo si = mService.getPackageShortcutForTest(packageName, shortcutId, userId);
+        if (si == null) {
+            return null;
+        }
+        return new File(si.getBitmapPath()).getName();
+    }
+
+    protected List<ShortcutInfo> getCallerShortcuts() {
+        final ShortcutPackage p = mService.getPackageShortcutForTest(
+                getCallingPackage(), getCallingUserId());
+        return p == null ? null : p.getAllShortcutsForTest();
+    }
+
+    protected ShortcutInfo getCallerShortcut(String shortcutId) {
+        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
+    }
+
+    protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
+        final List<ShortcutInfo>[] ret = new List[1];
+        runWithCaller(launcher, userId, () -> {
+            final ShortcutQuery q = new ShortcutQuery();
+            q.setQueryFlags(queryFlags);
+            ret[0] = mLauncherApps.getShortcuts(q, UserHandle.of(userId));
+        });
+        return ret[0];
+    }
+
+    protected List<ShortcutInfo> getLauncherPinnedShortcuts(String launcher, int userId) {
+        return getLauncherShortcuts(launcher, userId, ShortcutQuery.FLAG_GET_PINNED);
+    }
+
+    protected ShortcutInfo getShortcutInfoAsLauncher(String packageName, String shortcutId,
+            int userId) {
+        final List<ShortcutInfo> infoList =
+                mLauncherApps.getShortcutInfo(packageName, list(shortcutId),
+                        UserHandle.of(userId));
+        assertEquals("No shortcutInfo found (or too many of them)", 1, infoList.size());
+        return infoList.get(0);
+    }
+
+    protected Intent genPackageAddIntent(String pakcageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
+        i.setData(Uri.parse("package:" + pakcageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        return i;
+    }
+
+    protected Intent genPackageDeleteIntent(String pakcageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_REMOVED);
+        i.setData(Uri.parse("package:" + pakcageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        return i;
+    }
+
+    protected Intent genPackageUpdateIntent(String pakcageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_ADDED);
+        i.setData(Uri.parse("package:" + pakcageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        i.putExtra(Intent.EXTRA_REPLACING, true);
+        return i;
+    }
+
+    protected Intent genPackageDataClear(String packageName, int userId) {
+        Intent i = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED);
+        i.setData(Uri.parse("package:" + packageName));
+        i.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        return i;
+    }
+
+    protected void assertExistsAndShadow(ShortcutPackageItem spi) {
+        assertNotNull(spi);
+        assertTrue(spi.getPackageInfo().isShadow());
+    }
+
+    protected File makeFile(File baseDirectory, String... paths) {
+        File ret = baseDirectory;
+
+        for (String path : paths) {
+            ret = new File(ret, path);
+        }
+
+        return ret;
+    }
+
+    protected boolean bitmapDirectoryExists(String packageName, int userId) {
+        final File path = new File(mService.getUserBitmapFilePath(userId), packageName);
+        return path.isDirectory();
+    }
+    protected static ShortcutQuery buildQuery(long changedSince,
+            String packageName, ComponentName componentName,
+            /* @ShortcutQuery.QueryFlags */ int flags) {
+        return buildQuery(changedSince, packageName, null, componentName, flags);
+    }
+
+    protected static ShortcutQuery buildQuery(long changedSince,
+            String packageName, List<String> shortcutIds, ComponentName componentName,
+            /* @ShortcutQuery.QueryFlags */ int flags) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setChangedSince(changedSince);
+        q.setPackage(packageName);
+        q.setShortcutIds(shortcutIds);
+        q.setActivity(componentName);
+        q.setQueryFlags(flags);
+        return q;
+    }
+
+    protected static ShortcutQuery buildAllQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
+    protected static ShortcutQuery buildPinnedQuery(String packageName) {
+        final ShortcutQuery q = new ShortcutQuery();
+        q.setPackage(packageName);
+        q.setQueryFlags(ShortcutQuery.FLAG_GET_PINNED);
+        return q;
+    }
+
+    protected void backupAndRestore() {
+        int prevUid = mInjectedCallingUid;
+
+        mInjectedCallingUid = Process.SYSTEM_UID; // Only system can call it.
+
+        dumpsysOnLogcat("Before backup");
+
+        final byte[] payload =  mService.getBackupPayload(USER_0);
+        if (ENABLE_DUMP) {
+            final String xml = new String(payload);
+            Log.v(TAG, "Backup payload:");
+            for (String line : xml.split("\n")) {
+                Log.v(TAG, line);
+            }
+        }
+
+        // Before doing anything else, uninstall all packages.
+        for (int userId : list(USER_0, USER_P0)) {
+            for (String pkg : list(CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+                    LAUNCHER_1, LAUNCHER_2, LAUNCHER_3)) {
+                uninstallPackage(userId, pkg);
+            }
+        }
+
+        shutdownServices();
+
+        deleteAllSavedFiles();
+
+        initService();
+        mService.applyRestore(payload, USER_0);
+
+        // handleUnlockUser will perform the gone package check, but it shouldn't remove
+        // shadow information.
+        mService.handleUnlockUser(USER_0);
+
+        dumpsysOnLogcat("After restore");
+
+        mInjectedCallingUid = prevUid;
+    }
+
+    protected void prepareCrossProfileDataSet() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"),
+                    makeShortcut("x4"), makeShortcut("x5"), makeShortcut("x6"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s1", "s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s1", "s2", "s3"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s4"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s2", "s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s2", "s3", "s4"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s5"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s6"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list(), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_4, list(), HANDLE_USER_0);
+        });
+
+        // Launcher on a managed profile is referring ot user 0!
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3", "s4"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s3", "s4", "s5"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("s3", "s4", "s5", "s6"),
+                    HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s4", "s1"), HANDLE_USER_P0);
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("x4", "x5"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("x4", "x5", "x6"), HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("x4", "x5", "x6", "x1"),
+                    HANDLE_USER_10);
+        });
+
+        // Then remove some dynamic shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list()));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("x1"), makeShortcut("x2"), makeShortcut("x3"))));
+        });
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
new file mode 100644
index 0000000..c11be7a
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -0,0 +1,5578 @@
+/*
+ * 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.pm;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDisabled;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamic;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllDynamicOrPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllEnabled;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIcon;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconFile;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIconResId;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveIntents;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllHaveTitle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllImmutable;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllKeyFieldsOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllManifest;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveIntents;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotHaveTitle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotKeyFieldsOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllNotManifest;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllStringsResolved;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertAllUnique;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBitmapSize;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertBundleEmpty;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackNotReceived;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCallbackReceived;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertCannotUpdateImmutable;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicAndPinned;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicOnly;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertDynamicShortcutCountExceeded;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertEmpty;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertShortcutIds;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.filterByActivity;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.findShortcut;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.hashSet;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.makeBundle;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.pfdToBitmap;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.resetAll;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+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 android.Manifest.permission;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.ShortcutInfo;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.CompressFormat;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Process;
+import android.os.UserHandle;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.frameworks.servicestests.R;
+import com.android.server.pm.ShortcutService.ConfigConstants;
+import com.android.server.pm.ShortcutService.FileOutputStreamWithPath;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
+
+import org.mockito.ArgumentCaptor;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Tests for ShortcutService and ShortcutManager.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest1 \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+
+
+ * TODO More tests for pinning + manifest shortcuts
+ * TODO Manifest shortcuts + app upgrade -> launcher callback.
+ *      Also locale change should trigger launcehr callbacks too, when they use strign resoucres.
+ *      (not implemented yet.)
+ * TODO: Add checks with assertAllNotHaveIcon()
+ * TODO: Detailed test for hasShortcutPermissionInner().
+ * TODO: Add tests for the command line functions too.
+ */
+@SmallTest
+public class ShortcutManagerTest1 extends BaseShortcutManagerTest {
+
+    /**
+     * Test for the first launch path, no settings file available.
+     */
+    public void testFirstInitialize() {
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+    }
+
+    /**
+     * Test for {@link ShortcutService#getLastResetTimeLocked()} and
+     * {@link ShortcutService#getNextResetTimeLocked()}.
+     */
+    public void testUpdateAndGetNextResetTimeLocked() {
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock.
+        mInjectedCurrentTimeMillis += 100;
+
+        // Shouldn't have changed.
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock, almost the reset time.
+        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
+
+        // Shouldn't have changed.
+        assertResetTimes(START_TIME, START_TIME + INTERVAL);
+
+        // Advance clock.
+        mInjectedCurrentTimeMillis += 1;
+
+        assertResetTimes(START_TIME + INTERVAL, START_TIME + 2 * INTERVAL);
+
+        // Advance further; 4 hours since start.
+        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
+
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+    }
+
+    /**
+     * Test for the restoration from saved file.
+     */
+    public void testInitializeFromSavedFile() {
+
+        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+
+        mService.saveBaseStateLocked();
+
+        dumpBaseStateFile();
+
+        mService.saveDirtyInfo();
+
+        // Restore.
+        initService();
+
+        assertResetTimes(START_TIME + 4 * INTERVAL, START_TIME + 5 * INTERVAL);
+    }
+
+    /**
+     * Test for the restoration from restored file.
+     */
+    public void testLoadFromBrokenFile() {
+        // TODO Add various broken cases.
+    }
+
+    public void testLoadConfig() {
+        mService.updateConfigurationLocked(
+                ConfigConstants.KEY_RESET_INTERVAL_SEC + "=123,"
+                        + ConfigConstants.KEY_MAX_SHORTCUTS + "=4,"
+                        + ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=5,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+                        + ConfigConstants.KEY_ICON_FORMAT + "=WEBP,"
+                        + ConfigConstants.KEY_ICON_QUALITY + "=75");
+        assertEquals(123000, mService.getResetIntervalForTest());
+        assertEquals(4, mService.getMaxDynamicShortcutsForTest());
+        assertEquals(5, mService.getMaxUpdatesPerIntervalForTest());
+        assertEquals(100, mService.getMaxIconDimensionForTest());
+        assertEquals(CompressFormat.WEBP, mService.getIconPersistFormatForTest());
+        assertEquals(75, mService.getIconPersistQualityForTest());
+
+        mInjectedIsLowRamDevice = true;
+        mService.updateConfigurationLocked(
+                ConfigConstants.KEY_MAX_ICON_DIMENSION_DP + "=100,"
+                        + ConfigConstants.KEY_MAX_ICON_DIMENSION_DP_LOWRAM + "=50,"
+                        + ConfigConstants.KEY_ICON_FORMAT + "=JPEG");
+        assertEquals(ShortcutService.DEFAULT_RESET_INTERVAL_SEC * 1000,
+                mService.getResetIntervalForTest());
+
+        assertEquals(ShortcutService.DEFAULT_MAX_SHORTCUTS_PER_APP,
+                mService.getMaxDynamicShortcutsForTest());
+
+        assertEquals(ShortcutService.DEFAULT_MAX_UPDATES_PER_INTERVAL,
+                mService.getMaxUpdatesPerIntervalForTest());
+
+        assertEquals(50, mService.getMaxIconDimensionForTest());
+
+        assertEquals(CompressFormat.JPEG, mService.getIconPersistFormatForTest());
+
+        assertEquals(ShortcutService.DEFAULT_ICON_PERSIST_QUALITY,
+                mService.getIconPersistQualityForTest());
+    }
+
+    // === Test for app side APIs ===
+
+    /** Test for {@link android.content.pm.ShortcutManager#getMaxShortcutCountForActivity()} */
+    public void testGetMaxDynamicShortcutCount() {
+        assertEquals(MAX_SHORTCUTS, mManager.getMaxShortcutCountForActivity());
+    }
+
+    /** Test for {@link android.content.pm.ShortcutManager#getRemainingCallCount()} */
+    public void testGetRemainingCallCount() {
+        assertEquals(MAX_UPDATES_PER_INTERVAL, mManager.getRemainingCallCount());
+    }
+
+    public void testGetIconMaxDimensions() {
+        assertEquals(MAX_ICON_DIMENSION, mManager.getIconMaxWidth());
+        assertEquals(MAX_ICON_DIMENSION, mManager.getIconMaxHeight());
+    }
+
+    /** Test for {@link android.content.pm.ShortcutManager#getRateLimitResetTime()} */
+    public void testGetRateLimitResetTime() {
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL + 50;
+
+        assertEquals(START_TIME + 5 * INTERVAL, mManager.getRateLimitResetTime());
+    }
+
+    public void testSetDynamicShortcuts() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.icon1);
+        final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.icon2));
+
+        final ShortcutInfo si1 = makeShortcut(
+                "shortcut1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                icon1,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo si2 = makeShortcut(
+                "shortcut2",
+                "Title 2",
+                /* activity */ null,
+                icon2,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2");
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // TODO: Check fields
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1");
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list()));
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        dumpsysOnLogcat();
+
+        mInjectedCurrentTimeMillis++; // Need to advance the clock for reset to work.
+        mService.resetThrottlingInner(UserHandle.USER_SYSTEM);
+
+        dumpsysOnLogcat();
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2, si3)));
+        assertEquals(2, mManager.getDynamicShortcuts().size());
+
+        // TODO Check max number
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+    }
+
+    public void testAddDynamicShortcuts() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1");
+
+        assertTrue(mManager.addDynamicShortcuts(list(si2, si3)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        // This should not crash.  It'll still consume the quota.
+        assertTrue(mManager.addDynamicShortcuts(list()));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        mInjectedCurrentTimeMillis += INTERVAL; // reset
+
+        // Add with the same ID
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("shortcut1"))));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        // TODO Check max number
+
+        // TODO Check fields.
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+    }
+
+    public void testDeleteDynamicShortcuts() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+        final ShortcutInfo si4 = makeShortcut("shortcut4");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3, si4)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3", "shortcut4");
+
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mManager.removeDynamicShortcuts(list("shortcut1"));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3", "shortcut4");
+
+        mManager.removeDynamicShortcuts(list("shortcut1"));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3", "shortcut4");
+
+        mManager.removeDynamicShortcuts(list("shortcutXXX"));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut2", "shortcut3", "shortcut4");
+
+        mManager.removeDynamicShortcuts(list("shortcut2", "shortcut4"));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut3");
+
+        mManager.removeDynamicShortcuts(list("shortcut3"));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()));
+
+        // Still 2 calls left.
+        assertEquals(2, mManager.getRemainingCallCount());
+    }
+
+    public void testDeleteAllDynamicShortcuts() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+        final ShortcutInfo si2 = makeShortcut("shortcut2");
+        final ShortcutInfo si3 = makeShortcut("shortcut3");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mManager.getDynamicShortcuts()),
+                "shortcut1", "shortcut2", "shortcut3");
+
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mManager.removeAllDynamicShortcuts();
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // Note delete shouldn't affect throttling, so...
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+
+        // This should still work.
+        assertTrue(mManager.setDynamicShortcuts(list(si1, si2, si3)));
+        assertEquals(3, mManager.getDynamicShortcuts().size());
+
+        // Still 1 call left
+        assertEquals(1, mManager.getRemainingCallCount());
+    }
+
+    public void testIcons() throws IOException {
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+        final Icon res64x64 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
+        final Icon res512x512 = Icon.createWithResource(getTestContext(), R.drawable.black_512x512);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+        final Icon bmp64x64 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_64x64));
+        final Icon bmp512x512 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_512x512));
+
+        // Set from package 1
+        setCaller(CALLING_PACKAGE_1);
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIcon("res32x32", res32x32),
+                makeShortcutWithIcon("res64x64", res64x64),
+                makeShortcutWithIcon("bmp32x32", bmp32x32),
+                makeShortcutWithIcon("bmp64x64", bmp64x64),
+                makeShortcutWithIcon("bmp512x512", bmp512x512),
+                makeShortcut("none")
+        )));
+
+        // getDynamicShortcuts() shouldn't return icons, thus assertAllNotHaveIcon().
+        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+                "res32x32",
+                "res64x64",
+                "bmp32x32",
+                "bmp64x64",
+                "bmp512x512",
+                "none");
+
+        // Call from another caller with the same ID, just to make sure storage is per-package.
+        setCaller(CALLING_PACKAGE_2);
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIcon("res32x32", res512x512),
+                makeShortcutWithIcon("res64x64", res512x512),
+                makeShortcutWithIcon("none", res512x512)
+        )));
+        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+                "res32x32",
+                "res64x64",
+                "none");
+
+        // Different profile.  Note the names and the contents don't match.
+        setCaller(CALLING_PACKAGE_1, USER_P0);
+        assertTrue(mManager.setDynamicShortcuts(list(
+                makeShortcutWithIcon("res32x32", res512x512),
+                makeShortcutWithIcon("bmp32x32", bmp512x512)
+        )));
+        assertShortcutIds(assertAllNotHaveIcon(mManager.getDynamicShortcuts()),
+                "res32x32",
+                "bmp32x32");
+
+        // Re-initialize and load from the files.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Load from launcher.
+        Bitmap bmp;
+
+        setCaller(LAUNCHER_1);
+        // Check hasIconResource()/hasIconFile().
+        assertShortcutIds(assertAllHaveIconResId(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0))),
+                "res32x32");
+
+        assertShortcutIds(assertAllHaveIconResId(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0))),
+                "res64x64");
+
+        assertShortcutIds(assertAllHaveIconFile(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0))),
+                "bmp32x32");
+
+        assertShortcutIds(assertAllHaveIconFile(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0))),
+                "bmp64x64");
+
+        assertShortcutIds(assertAllHaveIconFile(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0))),
+                "bmp512x512");
+
+        assertShortcutIds(assertAllHaveIconResId(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0))),
+                "res32x32");
+        assertShortcutIds(assertAllHaveIconFile(
+                list(getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0))),
+                "bmp32x32");
+
+        // Check
+        assertEquals(
+                R.drawable.black_32x32,
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_0)));
+
+        assertEquals(
+                R.drawable.black_64x64,
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res64x64", USER_0)));
+
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
+        assertEquals(
+                0, // because it's not a resource
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_0)));
+        assertBitmapSize(32, 32, bmp);
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp64x64", USER_0)));
+        assertBitmapSize(64, 64, bmp);
+
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp512x512", USER_0)));
+        assertBitmapSize(128, 128, bmp);
+
+        assertEquals(
+                R.drawable.black_512x512,
+                mLauncherApps.getShortcutIconResId(
+                        getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "res32x32", USER_P0)));
+        // Should be 512x512, so shrunk.
+        bmp = pfdToBitmap(mLauncherApps.getShortcutIconFd(
+                getShortcutInfoAsLauncher(CALLING_PACKAGE_1, "bmp32x32", USER_P0)));
+        assertBitmapSize(128, 128, bmp);
+
+        // Also check the overload APIs too.
+        assertEquals(
+                R.drawable.black_32x32,
+                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_0));
+        assertEquals(
+                R.drawable.black_64x64,
+                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res64x64", HANDLE_USER_0));
+        assertEquals(
+                R.drawable.black_512x512,
+                mLauncherApps.getShortcutIconResId(CALLING_PACKAGE_1, "res32x32", HANDLE_USER_P0));
+        bmp = pfdToBitmap(
+                mLauncherApps.getShortcutIconFd(CALLING_PACKAGE_1, "bmp32x32", HANDLE_USER_P0));
+        assertBitmapSize(128, 128, bmp);
+    }
+
+    public void testCleanupDanglingBitmaps() throws Exception {
+        assertBitmapDirectories(USER_0, EMPTY_STRINGS);
+        assertBitmapDirectories(USER_10, EMPTY_STRINGS);
+
+        // Make some shortcuts with bitmap icons.
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("s1", bmp32x32),
+                    makeShortcutWithIcon("s2", bmp32x32),
+                    makeShortcutWithIcon("s3", bmp32x32)
+            ));
+        });
+
+        // Increment the time (which actually we don't have to), which is used for filenames.
+        mInjectedCurrentTimeMillis++;
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("s4", bmp32x32),
+                    makeShortcutWithIcon("s5", bmp32x32),
+                    makeShortcutWithIcon("s6", bmp32x32)
+            ));
+        });
+
+        // Increment the time, which is used for filenames.
+        mInjectedCurrentTimeMillis++;
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            mManager.setDynamicShortcuts(list(
+            ));
+        });
+
+        // For USER-10, let's try without updating the times.
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("10s1", bmp32x32),
+                    makeShortcutWithIcon("10s2", bmp32x32),
+                    makeShortcutWithIcon("10s3", bmp32x32)
+            ));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("10s4", bmp32x32),
+                    makeShortcutWithIcon("10s5", bmp32x32),
+                    makeShortcutWithIcon("10s6", bmp32x32)
+            ));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_10, () -> {
+            mManager.setDynamicShortcuts(list(
+            ));
+        });
+
+        dumpsysOnLogcat();
+
+        // Check files and directories.
+        // Package 3 has no bitmaps, so we don't create a directory.
+        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
+        assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
+
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_1,
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3")
+        );
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_2,
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6")
+        );
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_3,
+                EMPTY_STRINGS
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_1,
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3")
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_2,
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6")
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_3,
+                EMPTY_STRINGS
+        );
+
+        // Then create random directories and files.
+        makeFile(mService.getUserBitmapFilePath(USER_0), "a.b.c").mkdir();
+        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f").mkdir();
+        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "123").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_0), "d.e.f", "456").createNewFile();
+
+        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_3).mkdir();
+
+        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "1").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "2").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "3").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_0), CALLING_PACKAGE_1, "4").createNewFile();
+
+        makeFile(mService.getUserBitmapFilePath(USER_10), "10a.b.c").mkdir();
+        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f").mkdir();
+        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "123").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_10), "10d.e.f", "456").createNewFile();
+
+        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "1").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "2").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "3").createNewFile();
+        makeFile(mService.getUserBitmapFilePath(USER_10), CALLING_PACKAGE_2, "4").createNewFile();
+
+        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3,
+                "a.b.c", "d.e.f");
+
+        // Save and load.  When a user is loaded, we do the cleanup.
+        mService.saveDirtyInfo();
+        initService();
+
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_10);
+        mService.handleUnlockUser(20); // Make sure the logic will still work for nonexistent user.
+
+        // The below check is the same as above, except this time USER_0 use the CALLING_PACKAGE_3
+        // directory.
+
+        assertBitmapDirectories(USER_0, CALLING_PACKAGE_1, CALLING_PACKAGE_2, CALLING_PACKAGE_3);
+        assertBitmapDirectories(USER_10, CALLING_PACKAGE_1, CALLING_PACKAGE_2);
+
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_1,
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s1"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s2"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_1, "s3")
+        );
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_2,
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s4"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s5"),
+                getBitmapFilename(USER_0, CALLING_PACKAGE_2, "s6")
+        );
+        assertBitmapFiles(USER_0, CALLING_PACKAGE_3,
+                EMPTY_STRINGS
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_1,
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s1"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s2"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_1, "10s3")
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_2,
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s4"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s5"),
+                getBitmapFilename(USER_10, CALLING_PACKAGE_2, "10s6")
+        );
+        assertBitmapFiles(USER_10, CALLING_PACKAGE_3,
+                EMPTY_STRINGS
+        );
+    }
+
+    protected void checkShrinkBitmap(int expectedWidth, int expectedHeight, int resId, int maxSize) {
+        assertBitmapSize(expectedWidth, expectedHeight,
+                ShortcutService.shrinkBitmap(BitmapFactory.decodeResource(
+                        getTestContext().getResources(), resId),
+                        maxSize));
+    }
+
+    public void testShrinkBitmap() {
+        checkShrinkBitmap(32, 32, R.drawable.black_512x512, 32);
+        checkShrinkBitmap(511, 511, R.drawable.black_512x512, 511);
+        checkShrinkBitmap(512, 512, R.drawable.black_512x512, 512);
+
+        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4096);
+        checkShrinkBitmap(1024, 4096, R.drawable.black_1024x4096, 4100);
+        checkShrinkBitmap(512, 2048, R.drawable.black_1024x4096, 2048);
+
+        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4096);
+        checkShrinkBitmap(4096, 1024, R.drawable.black_4096x1024, 4100);
+        checkShrinkBitmap(2048, 512, R.drawable.black_4096x1024, 2048);
+    }
+
+    protected File openIconFileForWriteAndGetPath(int userId, String packageName)
+            throws IOException {
+        // Shortcut IDs aren't used in the path, so just pass the same ID.
+        final FileOutputStreamWithPath out =
+                mService.openIconFileForWrite(userId, makePackageShortcut(packageName, "id"));
+        out.close();
+        return out.getFile();
+    }
+
+    public void testOpenIconFileForWrite() throws IOException {
+        mInjectedCurrentTimeMillis = 1000;
+
+        final File p10_1_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+        final File p10_2_1 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+        final File p10_2_2 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+
+        final File p11_1_1 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+        final File p11_1_2 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+        mInjectedCurrentTimeMillis++;
+
+        final File p10_1_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_4 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+        final File p10_1_5 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_1);
+
+        final File p10_2_3 = openIconFileForWriteAndGetPath(10, CALLING_PACKAGE_2);
+        final File p11_1_3 = openIconFileForWriteAndGetPath(11, CALLING_PACKAGE_1);
+
+        // Make sure their paths are all unique
+        assertAllUnique(list(
+                p10_1_1,
+                p10_1_2,
+                p10_1_3,
+                p10_1_4,
+                p10_1_5,
+
+                p10_2_1,
+                p10_2_2,
+                p10_2_3,
+
+                p11_1_1,
+                p11_1_2,
+                p11_1_3
+        ));
+
+        // Check each set has the same parent.
+        assertEquals(p10_1_1.getParent(), p10_1_2.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_3.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_4.getParent());
+        assertEquals(p10_1_1.getParent(), p10_1_5.getParent());
+
+        assertEquals(p10_2_1.getParent(), p10_2_2.getParent());
+        assertEquals(p10_2_1.getParent(), p10_2_3.getParent());
+
+        assertEquals(p11_1_1.getParent(), p11_1_2.getParent());
+        assertEquals(p11_1_1.getParent(), p11_1_3.getParent());
+
+        // Check the parents are still unique.
+        assertAllUnique(list(
+                p10_1_1.getParent(),
+                p10_2_1.getParent(),
+                p11_1_1.getParent()
+        ));
+
+        // All files created at the same time for the same package/user, expcet for the first ones,
+        // will have "_" in the path.
+        assertFalse(p10_1_1.getName().contains("_"));
+        assertTrue(p10_1_2.getName().contains("_"));
+        assertFalse(p10_1_3.getName().contains("_"));
+        assertTrue(p10_1_4.getName().contains("_"));
+        assertTrue(p10_1_5.getName().contains("_"));
+
+        assertFalse(p10_2_1.getName().contains("_"));
+        assertTrue(p10_2_2.getName().contains("_"));
+        assertFalse(p10_2_3.getName().contains("_"));
+
+        assertFalse(p11_1_1.getName().contains("_"));
+        assertTrue(p11_1_2.getName().contains("_"));
+        assertFalse(p11_1_3.getName().contains("_"));
+    }
+
+    public void testUpdateShortcuts() {
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcut("s2"),
+                    makeShortcut("s3"),
+                    makeShortcut("s4"),
+                    makeShortcut("s5")
+            )));
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcut("s2"),
+                    makeShortcut("s3"),
+                    makeShortcut("s4"),
+                    makeShortcut("s5")
+            )));
+        });
+        runWithCaller(LAUNCHER_1, UserHandle.USER_SYSTEM, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2", "s3"),
+                    getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s4", "s5"),
+                    getCallingUser());
+        });
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.removeDynamicShortcuts(list("s1"));
+            mManager.removeDynamicShortcuts(list("s2"));
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            mManager.removeDynamicShortcuts(list("s1"));
+            mManager.removeDynamicShortcuts(list("s3"));
+            mManager.removeDynamicShortcuts(list("s5"));
+        });
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s3", "s4", "s5");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s2", "s4");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s4", "s5");
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            ShortcutInfo s2 = makeShortcutBuilder()
+                    .setId("s2")
+                    .setIcon(Icon.createWithResource(getTestContext(), R.drawable.black_32x32))
+                    .build();
+
+            ShortcutInfo s4 = makeShortcutBuilder()
+                    .setId("s4")
+                    .setTitle("new title")
+                    .build();
+
+            mManager.updateShortcuts(list(s2, s4));
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            ShortcutInfo s2 = makeShortcutBuilder()
+                    .setId("s2")
+                    .setIntent(makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
+                            "key1", "val1"))
+                    .build();
+
+            ShortcutInfo s4 = makeShortcutBuilder()
+                    .setId("s4")
+                    .setIntent(new Intent(Intent.ACTION_ALL_APPS))
+                    .build();
+
+            mManager.updateShortcuts(list(s2, s4));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s3", "s4", "s5");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+
+            ShortcutInfo s = getCallerShortcut("s2");
+            assertTrue(s.hasIconResource());
+            assertEquals(R.drawable.black_32x32, s.getIconResourceId());
+            assertEquals("Title-s2", s.getTitle());
+
+            s = getCallerShortcut("s4");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("new title", s.getTitle());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mManager.getDynamicShortcuts()),
+                    "s2", "s4");
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s4", "s5");
+
+            ShortcutInfo s = getCallerShortcut("s2");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("Title-s2", s.getTitle());
+            assertEquals(Intent.ACTION_ANSWER, s.getIntent().getAction());
+            assertEquals(1, s.getIntent().getExtras().size());
+
+            s = getCallerShortcut("s4");
+            assertFalse(s.hasIconResource());
+            assertEquals(0, s.getIconResourceId());
+            assertEquals("Title-s4", s.getTitle());
+            assertEquals(Intent.ACTION_ALL_APPS, s.getIntent().getAction());
+            assertBundleEmpty(s.getIntent().getExtras());
+        });
+        // TODO Check with other fields too.
+
+        // TODO Check bitmap removal too.
+
+        runWithCaller(CALLING_PACKAGE_2, USER_11, () -> {
+            mManager.updateShortcuts(list());
+        });
+    }
+
+    // === Test for launcher side APIs ===
+
+    public void testGetShortcuts() {
+
+        // Set up shortcuts.
+
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 5000);
+        final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 1000);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+        final ShortcutInfo s2_3 = makeShortcutWithTimestampWithActivity("s3", 3000,
+                makeComponent(ShortcutActivity2.class));
+        final ShortcutInfo s2_4 = makeShortcutWithTimestampWithActivity("s4", 500,
+                makeComponent(ShortcutActivity.class));
+        assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+
+        setCaller(CALLING_PACKAGE_3);
+        final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s3", START_TIME + 5000);
+        assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+
+        setCaller(LAUNCHER_1);
+
+        // Get dynamic
+        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertAllStringsResolved(
+                assertShortcutIds(
+                        assertAllNotKeyFieldsOnly(
+                                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                        /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                        "s1", "s2")))));
+
+        // Get pinned
+        assertShortcutIds(
+                mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED), getCallingUser())
+                /* none */);
+
+        // Get both, with timestamp
+        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
+                        getCallingUser())),
+                "s2", "s3"))));
+
+        // FLAG_GET_KEY_FIELDS_ONLY
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser())),
+                "s2", "s3"))));
+
+        // Filter by activity
+        assertAllDynamic(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 0, CALLING_PACKAGE_2,
+                        new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                        ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC),
+                        getCallingUser())),
+                "s4"))));
+
+        // With ID.
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3"),
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser())),
+                "s3"))));
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3", "s2", "ss"),
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser())),
+                "s2", "s3"))));
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2, list("s3x", "s2x"),
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser()))
+                /* empty */))));
+        assertAllDynamic(assertAllNotHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2, list(),
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_KEY_FIELDS_ONLY),
+                        getCallingUser()))
+                /* empty */))));
+
+        // Pin some shortcuts.
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                list("s3", "s4"), getCallingUser());
+
+        // Pinned ones only
+        assertAllPinned(assertAllHaveTitle(assertAllNotHaveIntents(assertShortcutIds(
+                assertAllNotKeyFieldsOnly(mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 1000, CALLING_PACKAGE_2,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_PINNED),
+                        getCallingUser())),
+                "s3"))));
+
+        // All packages.
+        assertShortcutIds(assertAllNotKeyFieldsOnly(
+                mLauncherApps.getShortcuts(buildQuery(
+                        /* time =*/ 5000, /* package= */ null,
+                        /* activity =*/ null,
+                        ShortcutQuery.FLAG_GET_DYNAMIC | ShortcutQuery.FLAG_GET_PINNED),
+                        getCallingUser())),
+                "s1", "s3");
+
+        assertExpectException(
+                IllegalArgumentException.class, "package name must also be set", () -> {
+                    mLauncherApps.getShortcuts(buildQuery(
+                    /* time =*/ 0, /* package= */ null, list("id"),
+                    /* activity =*/ null, /* flags */ 0), getCallingUser());
+                });
+
+        // TODO More tests: pinned but dynamic.
+    }
+
+    public void testGetShortcuts_resolveStrings() throws Exception {
+        doAnswer(pmInvocation -> {
+            assertEquals(Process.SYSTEM_UID, mInjectedCallingUid);
+
+            final String packageName = (String) pmInvocation.getArguments()[0];
+            final int userId = (Integer) pmInvocation.getArguments()[1];
+
+            final Resources res = mock(Resources.class);
+            doAnswer(resInvocation -> {
+                final int resId = (Integer) resInvocation.getArguments()[0];
+
+                return "string-" + packageName + "-user:" + userId + "-res:" + resId;
+            }).when(res).getString(anyInt());
+            return res;
+        }).when(mMockPackageManager).getResourcesForApplicationAsUser(anyString(), anyInt());
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
+                    .setId("id")
+                    .setActivity(new ComponentName(mClientContext, "dummy"))
+                    .setTitleResId(10)
+                    .setTextResId(11)
+                    .setDisabledMessageResId(12)
+                    .setIntent(makeIntent("action", ShortcutActivity.class))
+                    .build();
+            mManager.setDynamicShortcuts(list(si));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(mClientContext)
+                    .setId("id")
+                    .setActivity(new ComponentName(mClientContext, "dummy"))
+                    .setTitleResId(10)
+                    .setTextResId(11)
+                    .setDisabledMessageResId(12)
+                    .setIntent(makeIntent("action", ShortcutActivity.class))
+                    .build();
+            mManager.setDynamicShortcuts(list(si));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            final ShortcutQuery q = new ShortcutQuery();
+            q.setQueryFlags(ShortcutQuery.FLAG_GET_DYNAMIC);
+
+            // USER 0
+            List<ShortcutInfo> ret = assertShortcutIds(
+                    assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_0)),
+                    "id");
+            assertEquals("string-com.android.test.1-user:0-res:10", ret.get(0).getTitle());
+            assertEquals("string-com.android.test.1-user:0-res:11", ret.get(0).getText());
+            assertEquals("string-com.android.test.1-user:0-res:12",
+                    ret.get(0).getDisabledMessage());
+
+            // USER P0
+            ret = assertShortcutIds(
+                    assertAllStringsResolved(mLauncherApps.getShortcuts(q, HANDLE_USER_P0)),
+                    "id");
+            assertEquals("string-com.android.test.1-user:20-res:10", ret.get(0).getTitle());
+            assertEquals("string-com.android.test.1-user:20-res:11", ret.get(0).getText());
+            assertEquals("string-com.android.test.1-user:20-res:12",
+                    ret.get(0).getDisabledMessage());
+        });
+    }
+
+    // TODO resource
+    public void testGetShortcutInfo() {
+        // Create shortcuts.
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcut(
+                "s1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo s1_2 = makeShortcut(
+                "s2",
+                "Title 2",
+                /* activity */ null,
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+        dumpsysOnLogcat();
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_1 = makeShortcut(
+                "s1",
+                "ABC",
+                makeComponent(ShortcutActivity2.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+        dumpsysOnLogcat();
+
+        // Pin some.
+        setCaller(LAUNCHER_1);
+
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                list("s2"), getCallingUser());
+
+        dumpsysOnLogcat();
+
+        // Delete some.
+        setCaller(CALLING_PACKAGE_1);
+        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+        mManager.removeDynamicShortcuts(list("s2"));
+        assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+
+        dumpsysOnLogcat();
+
+        setCaller(LAUNCHER_1);
+        List<ShortcutInfo> list;
+
+        // Note we don't guarantee the orders.
+        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                assertAllNotKeyFieldsOnly(
+                        mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
+                                list("s2", "s1", "s3", null), getCallingUser())))),
+                "s1", "s2");
+        assertEquals("Title 1", findById(list, "s1").getTitle());
+        assertEquals("Title 2", findById(list, "s2").getTitle());
+
+        assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_1,
+                        list("s3"), getCallingUser())))
+                /* none */);
+
+        list = assertShortcutIds(assertAllHaveTitle(assertAllNotHaveIntents(
+                mLauncherApps.getShortcutInfo(CALLING_PACKAGE_2,
+                        list("s1", "s2", "s3"), getCallingUser()))),
+                "s1");
+        assertEquals("ABC", findById(list, "s1").getTitle());
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
+            final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
+
+            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+            final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
+            final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
+            assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
+            assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+        });
+
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2", "s3"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3", "s4", "s5"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
+                    list("s3"), getCallingUser());  // Note ID doesn't exist
+        });
+
+        // Delete some.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+            mManager.removeDynamicShortcuts(list("s2"));
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+
+            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+            mManager.removeDynamicShortcuts(list("s3"));
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+
+            assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4");
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+            mManager.removeDynamicShortcuts(list("s2"));
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+
+            assertEmpty(mManager.getDynamicShortcuts());
+        });
+
+        // Get pinned shortcuts from launcher
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
+                    "s2");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
+                    "s3", "s4");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))))
+                    /* none */);
+        });
+    }
+
+    /**
+     * This is similar to the above test, except it used "disable" instead of "remove".  It also
+     * does "enable".
+     */
+    public void testDisableAndEnableShortcuts() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
+            final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
+
+            assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+            final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
+            final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
+            assertTrue(mManager.setDynamicShortcuts(list(s2_2, s2_3, s2_4)));
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
+            assertTrue(mManager.setDynamicShortcuts(list(s3_2)));
+        });
+
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2", "s3"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3", "s4", "s5"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
+                    list("s3"), getCallingUser());  // Note ID doesn't exist
+        });
+
+        // Disable some.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+
+            mManager.disableShortcuts(list("s2"));
+
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+
+            // disable should work even if a shortcut is not dynamic, so try calling "remove" first
+            // here.
+            mManager.removeDynamicShortcuts(list("s3"));
+            mManager.disableShortcuts(list("s3"));
+
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+            assertShortcutIds(mManager.getDynamicShortcuts(), "s2", "s4");
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+
+            mManager.disableShortcuts(list("s2"));
+
+            assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+
+            assertEmpty(mManager.getDynamicShortcuts());
+            assertEmpty(getCallerShortcuts());
+        });
+
+        // Get pinned shortcuts from launcher
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllDisabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
+                    "s2");
+            assertFalse(mLauncherApps.startShortcut(
+                    CALLING_PACKAGE_1, "s2", null, null, HANDLE_USER_0));
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3", "s4");
+            assertFalse(mLauncherApps.startShortcut(
+                    CALLING_PACKAGE_2, "s3", null, null, HANDLE_USER_0));
+            assertTrue(mLauncherApps.startShortcut(
+                    CALLING_PACKAGE_2, "s4", null, null, HANDLE_USER_0));
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))))
+                    /* none */);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.enableShortcuts(list("s2"));
+
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+            assertShortcutIds(mManager.getDynamicShortcuts(), "s1");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(assertAllEnabled(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))),
+                    "s2");
+            assertTrue(mLauncherApps.startShortcut(
+                    CALLING_PACKAGE_1, "s2", null, null, HANDLE_USER_0));
+        });
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts_multi() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        dumpsysOnLogcat();
+
+        // Pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3", "s4"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2", "s4"), getCallingUser());
+        });
+
+        dumpsysOnLogcat();
+
+        // Delete some.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+            mManager.removeDynamicShortcuts(list("s3"));
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+        });
+
+        dumpsysOnLogcat();
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+            mManager.removeDynamicShortcuts(list("s1"));
+            mManager.removeDynamicShortcuts(list("s3"));
+            assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+        });
+
+        dumpsysOnLogcat();
+
+        // Get pinned shortcuts from launcher
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+        });
+
+        dumpsysOnLogcat();
+
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            // Launcher2 still has no pinned ones.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+                    /* none */);
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+                    /* none */);
+
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+
+            // Now pin some.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1", "s2"), getCallingUser());
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2"), getCallingUser());
+
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+
+            // S1 was not visible to it, so shouldn't be pinned.
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+        });
+
+        // Re-initialize and load from the files.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Load from file.
+        mService.handleUnlockUser(USER_0);
+
+        // Make sure package info is restored too.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s1", "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+                                    | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+                    "s2");
+        });
+
+        // Delete all dynamic.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.removeAllDynamicShortcuts();
+
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.removeAllDynamicShortcuts();
+
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2");
+
+            // from all packages.
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, null,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s2", "s3");
+
+            // Update pined.  Note s2 and s3 are actually available, but not visible to this
+            // launcher, so still can't be pinned.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+                    getCallingUser());
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+        });
+        // Re-publish s1.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s1"))));
+
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s3");
+
+            // Now "s1" is visible, so can be pinned.
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"),
+                    getCallingUser());
+
+            assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+                    "s1", "s3");
+        });
+
+        // Now clear pinned shortcuts.  First, from launcher 1.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
+
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2");
+        });
+
+        // Clear all pins from launcher 2.
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list(), getCallingUser());
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list(), getCallingUser());
+
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+    }
+
+    public void testPinShortcutAndGetPinnedShortcuts_crossProfile_plusLaunch() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+
+        // Pin some shortcuts and see the result.
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1", "s2", "s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s2", "s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1", "s2", "s3"), HANDLE_USER_10);
+        });
+
+        // Cross profile pinning.
+        final int PIN_AND_DYNAMIC = ShortcutQuery.FLAG_GET_PINNED | ShortcutQuery.FLAG_GET_DYNAMIC;
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+
+        // Remove some dynamic shortcuts.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_10)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_10)),
+                    "s1", "s2", "s3");
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+
+        // Save & load and make sure we still have the same information.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s2", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_P0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), HANDLE_USER_0)),
+                    "s3");
+            assertShortcutIds(assertAllDynamic(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, ShortcutQuery.FLAG_GET_DYNAMIC), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllDynamicOrPinned(
+                    mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+                    /* activity =*/ null, PIN_AND_DYNAMIC), HANDLE_USER_0)),
+                    "s1", "s3");
+
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_1, "s3", USER_0);
+
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s1", USER_0);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_2, "s2", USER_0);
+            assertShortcutLaunchable(CALLING_PACKAGE_2, "s3", USER_0);
+
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s1", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s2", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s3", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s4", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s5", USER_10);
+            assertShortcutNotLaunchable(CALLING_PACKAGE_1, "s6", USER_10);
+        });
+    }
+
+    public void testStartShortcut() {
+        // Create some shortcuts.
+        setCaller(CALLING_PACKAGE_1);
+        final ShortcutInfo s1_1 = makeShortcut(
+                "s1",
+                "Title 1",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+
+        final ShortcutInfo s1_2 = makeShortcut(
+                "s2",
+                "Title 2",
+                /* activity */ null,
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                /* weight */ 12);
+
+        assertTrue(mManager.setDynamicShortcuts(list(s1_1, s1_2)));
+
+        setCaller(CALLING_PACKAGE_2);
+        final ShortcutInfo s2_1 = makeShortcut(
+                "s1",
+                "ABC",
+                makeComponent(ShortcutActivity.class),
+                /* icon =*/ null,
+                makeIntent(Intent.ACTION_ANSWER, ShortcutActivity.class,
+                        "key1", "val1", "nest", makeBundle("key", 123)),
+                /* weight */ 10);
+        assertTrue(mManager.setDynamicShortcuts(list(s2_1)));
+
+        // Pin all.
+        setCaller(LAUNCHER_1);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                list("s1", "s2"), getCallingUser());
+
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                list("s1"), getCallingUser());
+
+        // Just to make it complicated, delete some.
+        setCaller(CALLING_PACKAGE_1);
+        mManager.removeDynamicShortcuts(list("s2"));
+
+        // intent and check.
+        setCaller(LAUNCHER_1);
+
+        Intent intent;
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s1", USER_0);
+        assertEquals(ShortcutActivity2.class.getName(), intent.getComponent().getClassName());
+
+
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_1, "s2", USER_0);
+        assertEquals(ShortcutActivity3.class.getName(), intent.getComponent().getClassName());
+
+        intent = launchShortcutAndGetIntent(CALLING_PACKAGE_2, "s1", USER_0);
+        assertEquals(ShortcutActivity.class.getName(), intent.getComponent().getClassName());
+
+        // TODO Check extra, etc
+    }
+
+    public void testLauncherCallback() throws Throwable {
+        LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
+
+        // Set listeners
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        waitOnMainThread();
+        ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3");
+
+        // From different package.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_2),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3");
+
+        // Different user, callback shouldn't be called.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        waitOnMainThread();
+        verify(c0, times(0)).onShortcutsChanged(
+                anyString(),
+                any(List.class),
+                any(UserHandle.class)
+        );
+
+        // Test for addDynamicShortcuts.
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            dumpsysOnLogcat("before addDynamicShortcuts");
+            assertTrue(mManager.addDynamicShortcuts(list(makeShortcut("s4"))));
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s1", "s2", "s3", "s4");
+
+        // Test for remove
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.removeDynamicShortcuts(list("s1"));
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s2", "s3", "s4");
+
+        // Test for update
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertTrue(mManager.updateShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"))));
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertShortcutIds(assertAllDynamic(shortcuts.getValue()),
+                "s2", "s3", "s4");
+
+        // Test for deleteAll
+        reset(c0);
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            mManager.removeAllDynamicShortcuts();
+        });
+
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertEquals(0, shortcuts.getValue().size());
+
+        // Remove CALLING_PACKAGE_2
+        reset(c0);
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_0, USER_0);
+
+        // Should get a callback with an empty list.
+        waitOnMainThread();
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_2),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0)
+        );
+        assertEquals(0, shortcuts.getValue().size());
+    }
+
+    public void testLauncherCallback_crossProfile() throws Throwable {
+        prepareCrossProfileDataSet();
+
+        final Handler h = new Handler(Looper.getMainLooper());
+
+        final LauncherApps.Callback c0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_3 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c0_4 = mock(LauncherApps.Callback.class);
+
+        final LauncherApps.Callback cP0_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_1 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c10_2 = mock(LauncherApps.Callback.class);
+        final LauncherApps.Callback c11_1 = mock(LauncherApps.Callback.class);
+
+        final List<LauncherApps.Callback> all =
+                list(c0_1, c0_2, c0_3, c0_4, cP0_1, c10_1, c11_1);
+
+        setDefaultLauncherChecker((pkg, userId) -> {
+            switch (userId) {
+                case USER_0:
+                    return LAUNCHER_2.equals(pkg);
+                case USER_P0:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_10:
+                    return LAUNCHER_1.equals(pkg);
+                case USER_11:
+                    return LAUNCHER_1.equals(pkg);
+                default:
+                    return false;
+            }
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> mLauncherApps.registerCallback(c0_1, h));
+        runWithCaller(LAUNCHER_2, USER_0, () -> mLauncherApps.registerCallback(c0_2, h));
+        runWithCaller(LAUNCHER_3, USER_0, () -> mLauncherApps.registerCallback(c0_3, h));
+        runWithCaller(LAUNCHER_4, USER_0, () -> mLauncherApps.registerCallback(c0_4, h));
+        runWithCaller(LAUNCHER_1, USER_P0, () -> mLauncherApps.registerCallback(cP0_1, h));
+        runWithCaller(LAUNCHER_1, USER_10, () -> mLauncherApps.registerCallback(c10_1, h));
+        runWithCaller(LAUNCHER_2, USER_10, () -> mLauncherApps.registerCallback(c10_2, h));
+        runWithCaller(LAUNCHER_1, USER_11, () -> mLauncherApps.registerCallback(c11_1, h));
+
+        // User 0.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.removeDynamicShortcuts(list());
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // User 0, different package.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            mManager.removeDynamicShortcuts(list());
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_0, CALLING_PACKAGE_3, "s1", "s2", "s3", "s4");
+        assertCallbackReceived(cP0_1, HANDLE_USER_0, CALLING_PACKAGE_3,
+                "s1", "s2", "s3", "s4", "s5", "s6");
+
+        // Work profile, but not running, so don't send notifications.
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.removeDynamicShortcuts(list());
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+
+        // Work profile, now running.
+        doAnswer(new AnswerIsUserRunning(false)).when(mMockUserManager).isUserRunning(anyInt());
+        doAnswer(new AnswerIsUserRunning(true)).when(mMockUserManager).isUserRunning(eq(USER_P0));
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            mManager.removeDynamicShortcuts(list());
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(c10_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c0_2, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s5");
+        assertCallbackReceived(cP0_1, HANDLE_USER_P0, CALLING_PACKAGE_1, "s1", "s2", "s3", "s4");
+
+        // Normal secondary user.
+
+        doAnswer(new AnswerIsUserRunning(false)).when(mMockUserManager).isUserRunning(anyInt());
+        doAnswer(new AnswerIsUserRunning(true)).when(mMockUserManager).isUserRunning(eq(USER_10));
+
+        resetAll(all);
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.removeDynamicShortcuts(list());
+        });
+        waitOnMainThread();
+
+        assertCallbackNotReceived(c0_1);
+        assertCallbackNotReceived(c0_2);
+        assertCallbackNotReceived(c0_3);
+        assertCallbackNotReceived(c0_4);
+        assertCallbackNotReceived(cP0_1);
+        assertCallbackNotReceived(c10_2);
+        assertCallbackNotReceived(c11_1);
+        assertCallbackReceived(c10_1, HANDLE_USER_10, CALLING_PACKAGE_1,
+                "x1", "x2", "x3", "x4", "x5");
+    }
+
+    // === Test for persisting ===
+
+    public void testSaveAndLoadUser_empty() {
+        assertTrue(mManager.setDynamicShortcuts(list()));
+
+        Log.i(TAG, "Saved state");
+        dumpsysOnLogcat();
+        dumpUserFile(0);
+
+        // Restore.
+        mService.saveDirtyInfo();
+        initService();
+
+        assertEquals(0, mManager.getDynamicShortcuts().size());
+    }
+
+    /**
+     * Try save and load, also stop/start the user.
+     */
+    public void testSaveAndLoadUser() {
+        // First, create some shortcuts and save.
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x16);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title1-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title1-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_16x64);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title2-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title2-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            final Icon icon1 = Icon.createWithResource(getTestContext(), R.drawable.black_64x64);
+            final Icon icon2 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                    getTestContext().getResources(), R.drawable.icon2));
+
+            final ShortcutInfo si1 = makeShortcut(
+                    "s1",
+                    "title10-1-1",
+                    makeComponent(ShortcutActivity.class),
+                    icon1,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity2.class,
+                            "key1", "val1", "nest", makeBundle("key", 123)),
+                        /* weight */ 10);
+
+            final ShortcutInfo si2 = makeShortcut(
+                    "s2",
+                    "title10-1-2",
+                        /* activity */ null,
+                    icon2,
+                    makeIntent(Intent.ACTION_ASSIST, ShortcutActivity3.class),
+                        /* weight */ 12);
+
+            assertTrue(mManager.setDynamicShortcuts(list(si1, si2)));
+
+            assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+            assertEquals(2, mManager.getRemainingCallCount());
+        });
+
+        mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM).setDefaultLauncherComponent(
+                new ComponentName("pkg1", "class"));
+
+        // Restore.
+        mService.saveDirtyInfo();
+        initService();
+
+        // Before the load, the map should be empty.
+        assertEquals(0, mService.getShortcutsForTest().size());
+
+        // this will pre-load the per-user info.
+        mService.handleUnlockUser(UserHandle.USER_SYSTEM);
+
+        // Now it's loaded.
+        assertEquals(1, mService.getShortcutsForTest().size());
+
+        runWithCaller(CALLING_PACKAGE_1, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title1-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title1-2", getCallerShortcut("s2").getTitle());
+        });
+        runWithCaller(CALLING_PACKAGE_2, UserHandle.USER_SYSTEM, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title2-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title2-2", getCallerShortcut("s2").getTitle());
+        });
+
+        assertEquals("pkg1", mService.getShortcutsForTest().get(UserHandle.USER_SYSTEM)
+                .getDefaultLauncherComponent().getPackageName());
+
+        // Start another user
+        mService.handleUnlockUser(USER_10);
+
+        // Now the size is 2.
+        assertEquals(2, mService.getShortcutsForTest().size());
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertShortcutIds(assertAllDynamic(assertAllHaveIntents(assertAllHaveIcon(
+                    mManager.getDynamicShortcuts()))), "s1", "s2");
+            assertEquals(2, mManager.getRemainingCallCount());
+
+            assertEquals("title10-1-1", getCallerShortcut("s1").getTitle());
+            assertEquals("title10-1-2", getCallerShortcut("s2").getTitle());
+        });
+        assertNull(mService.getShortcutsForTest().get(USER_10).getDefaultLauncherComponent());
+
+        // Try stopping the user
+        mService.handleCleanupUser(USER_10);
+
+        // Now it's unloaded.
+        assertEquals(1, mService.getShortcutsForTest().size());
+
+        // TODO Check all other fields
+    }
+
+    public void testCleanupPackage() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s0_1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s0_2"))));
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+                    HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+                    HANDLE_USER_0);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s0_1"),
+                    HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s0_2"),
+                    HANDLE_USER_0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s10_1"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s10_2"))));
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+                    HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+                    HANDLE_USER_10);
+        });
+        runWithCaller(LAUNCHER_2, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s10_1"),
+                    HANDLE_USER_10);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("s10_2"),
+                    HANDLE_USER_10);
+        });
+
+        // Remove all dynamic shortcuts; now all shortcuts are just pinned.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.removeAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.removeAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            mManager.removeAllDynamicShortcuts();
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            mManager.removeAllDynamicShortcuts();
+        });
+
+
+        final SparseArray<ShortcutUser> users =  mService.getShortcutsForTest();
+        assertEquals(2, users.size());
+        assertEquals(USER_0, users.keyAt(0));
+        assertEquals(USER_10, users.keyAt(1));
+
+        final ShortcutUser user0 =  users.get(USER_0);
+        final ShortcutUser user10 =  users.get(USER_10);
+
+
+        // Check the registered packages.
+        dumpsysOnLogcat();
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Nonexistent package.
+        uninstallPackage(USER_0, "abc");
+        mService.cleanUpPackageLocked("abc", USER_0, USER_0);
+
+        // No changes.
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_1", "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a package.
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_0, USER_0);
+
+        assertEquals(set(CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_10, LAUNCHER_1),
+                        PackageWithUser.of(USER_10, LAUNCHER_2)),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a launcher.
+        uninstallPackage(USER_10, LAUNCHER_1);
+        mService.cleanUpPackageLocked(LAUNCHER_1, USER_10, USER_10);
+
+        assertEquals(set(CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1, CALLING_PACKAGE_2),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_10, LAUNCHER_2)),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1", "s10_2");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove a package.
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_2, USER_10, USER_10);
+
+        assertEquals(set(CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_10, LAUNCHER_2)),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_10),
+                "s10_1");
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // Remove the other launcher from user 10 too.
+        uninstallPackage(USER_10, LAUNCHER_2);
+        mService.cleanUpPackageLocked(LAUNCHER_2, USER_10, USER_10);
+
+        assertEquals(set(CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(CALLING_PACKAGE_1),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(
+                set(),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+
+        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+
+        // More remove.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        mService.cleanUpPackageLocked(CALLING_PACKAGE_1, USER_10, USER_10);
+
+        assertEquals(set(CALLING_PACKAGE_2),
+                hashSet(user0.getAllPackagesForTest().keySet()));
+        assertEquals(set(),
+                hashSet(user10.getAllPackagesForTest().keySet()));
+        assertEquals(
+                set(PackageWithUser.of(USER_0, LAUNCHER_1),
+                        PackageWithUser.of(USER_0, LAUNCHER_2)),
+                hashSet(user0.getAllLaunchersForTest().keySet()));
+        assertEquals(set(),
+                hashSet(user10.getAllLaunchersForTest().keySet()));
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_1, USER_0),
+                "s0_2");
+        assertShortcutIds(getLauncherPinnedShortcuts(LAUNCHER_2, USER_0),
+                "s0_2");
+
+        // Note the pinned shortcuts on user-10 no longer referred, so they should both be removed.
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s0_1", USER_0);
+        assertShortcutExists(CALLING_PACKAGE_2, "s0_2", USER_0);
+        assertShortcutNotExists(CALLING_PACKAGE_1, "s10_1", USER_10);
+        assertShortcutNotExists(CALLING_PACKAGE_2, "s10_2", USER_10);
+
+        mService.saveDirtyInfo();
+    }
+
+    public void testHandleGonePackage_crossProfile() {
+        // Create some shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+        });
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Pin some.
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s1"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), UserHandle.of(USER_P0));
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s3"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s2"), HANDLE_USER_0);
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), UserHandle.of(USER_P0));
+
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+                    list("s1"), HANDLE_USER_0);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("s3"), HANDLE_USER_10);
+        });
+
+        // Check the state.
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Make sure all the information is persisted.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Start uninstalling.
+        uninstallPackage(USER_10, LAUNCHER_1);
+        mService.checkPackageChanges(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Uninstall.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        mService.checkPackageChanges(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_P0, LAUNCHER_1);
+        mService.checkPackageChanges(USER_0);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        mService.checkPackageChanges(USER_P0);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_P0, CALLING_PACKAGE_1);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicAndPinned(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        // Uninstall
+        uninstallPackage(USER_0, LAUNCHER_1);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_P0);
+        mService.handleUnlockUser(USER_10);
+
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_0));
+        assertDynamicOnly(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_P0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_P0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s2", USER_0));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_2, "s3", USER_0));
+
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s2", USER_10));
+        assertNull(getPackageShortcut(CALLING_PACKAGE_1, "s3", USER_10));
+    }
+
+    protected void checkCanRestoreTo(boolean expected, ShortcutPackageInfo spi,
+            int version, String... signatures) {
+        assertEquals(expected, spi.canRestoreTo(mService, genPackage(
+                "dummy", /* uid */ 0, version, signatures)));
+    }
+
+    public void testCanRestoreTo() {
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sig1");
+        addPackage(CALLING_PACKAGE_2, CALLING_UID_1, 10, "sig1", "sig2");
+
+        final ShortcutPackageInfo spi1 = ShortcutPackageInfo.generateForInstalledPackage(
+                mService, CALLING_PACKAGE_1, USER_0);
+        final ShortcutPackageInfo spi2 = ShortcutPackageInfo.generateForInstalledPackage(
+                mService, CALLING_PACKAGE_2, USER_0);
+
+        checkCanRestoreTo(true, spi1, 10, "sig1");
+        checkCanRestoreTo(true, spi1, 10, "x", "sig1");
+        checkCanRestoreTo(true, spi1, 10, "sig1", "y");
+        checkCanRestoreTo(true, spi1, 10, "x", "sig1", "y");
+        checkCanRestoreTo(true, spi1, 11, "sig1");
+
+        checkCanRestoreTo(false, spi1, 10 /* empty */);
+        checkCanRestoreTo(false, spi1, 10, "x");
+        checkCanRestoreTo(false, spi1, 10, "x", "y");
+        checkCanRestoreTo(false, spi1, 10, "x");
+        checkCanRestoreTo(false, spi1, 9, "sig1");
+
+        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2");
+        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1");
+        checkCanRestoreTo(true, spi2, 10, "sig1", "sig2", "y");
+        checkCanRestoreTo(true, spi2, 10, "sig2", "sig1", "y");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig1", "sig2", "y");
+        checkCanRestoreTo(true, spi2, 10, "x", "sig2", "sig1", "y");
+        checkCanRestoreTo(true, spi2, 11, "x", "sig2", "sig1", "y");
+
+        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x");
+        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1");
+        checkCanRestoreTo(false, spi2, 10, "sig1", "sig2x", "y");
+        checkCanRestoreTo(false, spi2, 10, "sig2", "sig1x", "y");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig1x", "sig2", "y");
+        checkCanRestoreTo(false, spi2, 10, "x", "sig2x", "sig1", "y");
+        checkCanRestoreTo(false, spi2, 11, "x", "sig2x", "sig1", "y");
+    }
+
+    public void testHandlePackageDelete() {
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+        setCaller(CALLING_PACKAGE_1, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(
+                makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
+        )));
+
+        setCaller(CALLING_PACKAGE_2, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_3, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_1, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_2, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_3, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDeleteIntent(CALLING_PACKAGE_1, USER_0));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDeleteIntent(CALLING_PACKAGE_2, USER_10));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        mInjectedPackages.remove(CALLING_PACKAGE_1);
+        mInjectedPackages.remove(CALLING_PACKAGE_3);
+
+        mService.handleUnlockUser(USER_0);
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        mService.handleUnlockUser(USER_10);
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+    }
+
+    /** Almost ame as testHandlePackageDelete, except it doesn't uninstall packages. */
+    public void testHandlePackageClearData() {
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+        setCaller(CALLING_PACKAGE_1, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(
+                makeShortcutWithIcon("s1", bmp32x32), makeShortcutWithIcon("s2", bmp32x32)
+        )));
+
+        setCaller(CALLING_PACKAGE_2, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_3, USER_0);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_1, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_2, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        setCaller(CALLING_PACKAGE_3, USER_10);
+        assertTrue(mManager.addDynamicShortcuts(list(makeShortcutWithIcon("s1", bmp32x32))));
+
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDataClear(CALLING_PACKAGE_1, USER_0));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageDataClear(CALLING_PACKAGE_2, USER_10));
+
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_0));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "s1", USER_10));
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_2, "s1", USER_10));
+        assertNotNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_3, "s1", USER_10));
+
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_0));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_1, USER_10));
+        assertFalse(bitmapDirectoryExists(CALLING_PACKAGE_2, USER_10));
+        assertTrue(bitmapDirectoryExists(CALLING_PACKAGE_3, USER_10));
+    }
+
+    public void testHandlePackageUpdate() throws Throwable {
+
+        // Set up shortcuts and launchers.
+
+        final Icon res32x32 = Icon.createWithResource(getTestContext(), R.drawable.black_32x32);
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcutWithIcon("s2", res32x32),
+                    makeShortcutWithIcon("s3", res32x32),
+                    makeShortcutWithIcon("s4", bmp32x32))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"),
+                    makeShortcutWithIcon("s2", bmp32x32))));
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("s1", res32x32))));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("s1", res32x32),
+                    makeShortcutWithIcon("s2", res32x32))));
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcutWithIcon("s1", bmp32x32),
+                    makeShortcutWithIcon("s2", bmp32x32))));
+        });
+
+        LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
+        LauncherApps.Callback c10 = mock(LauncherApps.Callback.class);
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.registerCallback(c0, new Handler(Looper.getMainLooper()));
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            mLauncherApps.registerCallback(c10, new Handler(Looper.getMainLooper()));
+        });
+
+        mInjectedCurrentTimeMillis = START_TIME + 100;
+
+        ArgumentCaptor<List> shortcuts;
+
+        // First, call the event without updating the versions.
+        reset(c0);
+        reset(c10);
+
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_10));
+
+        waitOnMainThread();
+
+        // Version not changed, so no callback.
+        verify(c0, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+        verify(c10, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+
+        // Next, update the version info for package 1.
+        reset(c0);
+        reset(c10);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+
+        // Then send the broadcast, to only user-0.
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageUpdateIntent(CALLING_PACKAGE_1, USER_0));
+
+        waitOnMainThread();
+
+        // User-0 should get the notification.
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0));
+
+        // User-10 shouldn't yet get the notification.
+        verify(c10, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+        assertShortcutIds(shortcuts.getValue(), "s1", "s2", "s3", "s4");
+        assertEquals(START_TIME,
+                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
+        assertEquals(START_TIME + 100,
+                findShortcut(shortcuts.getValue(), "s2").getLastChangedTimestamp());
+        assertEquals(START_TIME + 100,
+                findShortcut(shortcuts.getValue(), "s3").getLastChangedTimestamp());
+        assertEquals(START_TIME,
+                findShortcut(shortcuts.getValue(), "s4").getLastChangedTimestamp());
+
+        // Next, send unlock even on user-10.  Now we scan packages on this user and send a
+        // notification to the launcher.
+        mInjectedCurrentTimeMillis = START_TIME + 200;
+
+        doAnswer(new AnswerIsUserRunning(true)).when(mMockUserManager).isUserRunning(eq(USER_10));
+
+        reset(c0);
+        reset(c10);
+        mService.handleUnlockUser(USER_10);
+
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+
+        verify(c10).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                shortcuts.capture(),
+                eq(HANDLE_USER_10));
+
+        assertShortcutIds(shortcuts.getValue(), "s1", "s2");
+        assertEquals(START_TIME + 200,
+                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
+        assertEquals(START_TIME + 200,
+                findShortcut(shortcuts.getValue(), "s2").getLastChangedTimestamp());
+
+
+        // Do the same thing for package 2, which doesn't have resource icons.
+        mInjectedCurrentTimeMillis = START_TIME + 300;
+
+        reset(c0);
+        reset(c10);
+        updatePackageVersion(CALLING_PACKAGE_2, 10);
+
+        // Then send the broadcast, to only user-0.
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageUpdateIntent(CALLING_PACKAGE_2, USER_0));
+        mService.handleUnlockUser(USER_10);
+
+        waitOnMainThread();
+
+        verify(c0, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+
+        verify(c10, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_1),
+                any(List.class),
+                any(UserHandle.class));
+
+        // Do the same thing for package 3
+        mInjectedCurrentTimeMillis = START_TIME + 400;
+
+        reset(c0);
+        reset(c10);
+        updatePackageVersion(CALLING_PACKAGE_3, 100);
+
+        // Then send the broadcast, to only user-0.
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageUpdateIntent(CALLING_PACKAGE_3, USER_0));
+        mService.handleUnlockUser(USER_10);
+
+        waitOnMainThread();
+
+        shortcuts = ArgumentCaptor.forClass(List.class);
+        verify(c0).onShortcutsChanged(
+                eq(CALLING_PACKAGE_3),
+                shortcuts.capture(),
+                eq(HANDLE_USER_0));
+
+        // User 10 doesn't have package 3, so no callback.
+        verify(c10, times(0)).onShortcutsChanged(
+                eq(CALLING_PACKAGE_3),
+                any(List.class),
+                any(UserHandle.class));
+
+        assertShortcutIds(shortcuts.getValue(), "s1");
+        assertEquals(START_TIME + 400,
+                findShortcut(shortcuts.getValue(), "s1").getLastChangedTimestamp());
+    }
+
+    protected void prepareForBackupTest() {
+
+        prepareCrossProfileDataSet();
+
+        backupAndRestore();
+    }
+
+    /**
+     * Make sure the backup data doesn't have the following information:
+     * - Launchers on other users.
+     * - Non-backup app information.
+     *
+     * But restores all other infomation.
+     *
+     * It also omits the following pieces of information, but that's tested in
+     * {@link ShortcutManagerTest2#testShortcutInfoSaveAndLoad_forBackup}.
+     * - Unpinned dynamic shortcuts
+     * - Bitmaps
+     */
+    public void testBackupAndRestore() {
+        prepareForBackupTest();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreTwice() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        dumpsysOnLogcat("Before second backup");
+
+        backupAndRestore();
+
+        dumpsysOnLogcat("After second backup");
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_backupRestoreMultiple() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // This also shouldn't affect the result.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(
+                    makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"),
+                    makeShortcut("s4"), makeShortcut("s5"), makeShortcut("s6"))));
+        });
+
+        backupAndRestore();
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToNewVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 2);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 5);
+
+        checkBackupAndRestore_success();
+    }
+
+    public void testBackupAndRestore_restoreToSuperSetSignatures() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        // Change package signatures.
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 1, "sigx", CALLING_PACKAGE_1);
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 4, LAUNCHER_1, "sigy");
+
+        checkBackupAndRestore_success();
+    }
+
+    protected void checkBackupAndRestore_success() {
+        // Make sure non-system user is not restored.
+        final ShortcutUser userP0 = mService.getUserShortcutsLocked(USER_P0);
+        assertEquals(0, userP0.getAllPackagesForTest().size());
+        assertEquals(0, userP0.getAllLaunchersForTest().size());
+
+        // Make sure only "allowBackup" apps are restored, and are shadow.
+        final ShortcutUser user0 = mService.getUserShortcutsLocked(USER_0);
+        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_1));
+        assertExistsAndShadow(user0.getAllPackagesForTest().get(CALLING_PACKAGE_2));
+        assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_1)));
+        assertExistsAndShadow(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_2)));
+
+        assertNull(user0.getAllPackagesForTest().get(CALLING_PACKAGE_3));
+        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
+        assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
+
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty, not restored */ );
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty, not restored */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        // 3 shouldn't be backed up, so no pinned shortcuts.
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Launcher on a different profile shouldn't be restored.
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                            .size());
+            assertEquals(0,
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                            .size());
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+        });
+
+        // Package on a different profile, no restore.
+        installPackage(USER_P0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        // Restore launcher 2 on user 0.
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+
+        // Restoration of launcher2 shouldn't affect other packages; so do the same checks and
+        // make sure they still have the same result.
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s1");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* wasn't restored, so still empty */ );
+
+            assertEquals(0, mLauncherApps.getShortcuts(QUERY_ALL, HANDLE_USER_P0).size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+    }
+
+    public void testBackupAndRestore_publisherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    public void testBackupAndRestore_publisherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherNotRestored();
+    }
+
+    protected void checkBackupAndRestore_publisherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s1", "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherLowerVersion() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 0); // Lower version
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherWrongSignature() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    public void testBackupAndRestore_launcherNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_launcherNotRestored();
+    }
+
+    protected void checkBackupAndRestore_launcherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // s1 was pinned by launcher 1, which is not restored, yet, so we still see "s1" here.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        // Now we try to restore launcher 1.  Then we realize it's not restorable, so L1 has no pinned
+        // shortcuts.
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+
+            // Now CALLING_PACKAGE_1 realizes "s1" is no longer pinned.
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2");
+        });
+
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0)),
+                    "s2");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testBackupAndRestore_launcherAndPackageNoLongerBackupTarget() {
+        prepareForBackupTest();
+
+        // Note doing a backup & restore again here shouldn't affect the result.
+        backupAndRestore();
+
+        updatePackageInfo(CALLING_PACKAGE_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        updatePackageInfo(LAUNCHER_1,
+                pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
+
+        checkBackupAndRestore_publisherAndLauncherNotRestored();
+    }
+
+    protected void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+        installPackage(USER_0, CALLING_PACKAGE_1);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_2);
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3");
+        });
+
+        installPackage(USER_0, LAUNCHER_1);
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        installPackage(USER_0, LAUNCHER_2);
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+
+        // Because launcher 1 wasn't restored, "s1" is no longer pinned.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertShortcutIds(assertAllPinned(
+                    mManager.getPinnedShortcuts()),
+                    "s2", "s3");
+        });
+
+        installPackage(USER_0, CALLING_PACKAGE_3);
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(0, mManager.getDynamicShortcuts().size());
+            assertEquals(0, mManager.getPinnedShortcuts().size());
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0))
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_2), HANDLE_USER_0)),
+                    "s2", "s3");
+            assertShortcutIds(assertAllPinned(
+                    mLauncherApps.getShortcuts(buildAllQuery(CALLING_PACKAGE_3), HANDLE_USER_0))
+                    /* empty */);
+        });
+    }
+
+    public void testSaveAndLoad_crossProfile() {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5");
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "s1", "s2", "s3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "s1", "s2", "s3", "s4", "s5", "s6");
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_P0, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts())
+                    /* empty */);
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts())
+                    /* empty */);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()),
+                    "x1", "x2", "x3");
+            assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()),
+                    "x4", "x5");
+        });
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s1");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s1", "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s1", "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+            assertExpectException(
+                    SecurityException.class, "", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s2");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s2", "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s2", "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s2", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_3, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s3", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_4, USER_0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_4), HANDLE_USER_0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_P0)
+                    /* empty */);
+        });
+        runWithCaller(LAUNCHER_1, USER_P0, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_0),
+                    "s3", "s4");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_0),
+                    "s3", "s4", "s5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_0),
+                    "s3", "s4", "s5", "s6");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_P0),
+                    "s1", "s4");
+            assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_10);
+                    });
+        });
+        runWithCaller(LAUNCHER_1, USER_10, () -> {
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_1), HANDLE_USER_10),
+                    "x4", "x5");
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_2), HANDLE_USER_10)
+                    /* empty */);
+            assertShortcutIds(
+                    mLauncherApps.getShortcuts(buildPinnedQuery(CALLING_PACKAGE_3), HANDLE_USER_10)
+                    /* empty */);
+            assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_0);
+                    });
+            assertExpectException(
+                    SecurityException.class, "unrelated profile", () -> {
+                        mLauncherApps.getShortcuts(
+                                buildAllQuery(CALLING_PACKAGE_1), HANDLE_USER_P0);
+                    });
+        });
+    }
+
+    public void testOnApplicationActive_permission() {
+        assertExpectException(SecurityException.class, "Missing permission", () ->
+                mService.onApplicationActive(CALLING_PACKAGE_1, USER_0));
+
+        // Has permission, now it should pass.
+        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
+        mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+    }
+
+    public void testDumpsys_crossProfile() {
+        prepareCrossProfileDataSet();
+        dumpsysOnLogcat("test1", /* force= */ true);
+    }
+
+    public void testDumpsys_withIcons() throws IOException {
+        testIcons();
+        // Dump after having some icons.
+        dumpsysOnLogcat("test1", /* force= */ true);
+    }
+
+    public void testManifestShortcut_publishOnUnlockUser() {
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+
+        // Unlock user-0.
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Try on another user, with some packages uninstalled.
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        uninstallPackage(USER_10, CALLING_PACKAGE_3);
+
+        mService.handleUnlockUser(USER_10);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_10, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Now change the resources for package 1, and unlock again.
+        // But we still see *old* shortcuts, because the package version and install time
+        // hasn't changed.
+        shutdownServices();
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Do it again, but this time we change the app version, so we do detect the changes.
+        shutdownServices();
+
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        updatePackageLastUpdateTime(CALLING_PACKAGE_3, 1);
+
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Next, try removing all shortcuts, with some of them pinned.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms3"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2"), HANDLE_USER_0);
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_3, list("ms1"), HANDLE_USER_0);
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
+                    assertAllEnabled(mManager.getPinnedShortcuts())))),
+                    "ms3");
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
+                    assertAllEnabled(mManager.getPinnedShortcuts())))),
+                    "ms2");
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllManifest(
+                    assertAllEnabled(mManager.getPinnedShortcuts())))),
+                    "ms1");
+        });
+
+        shutdownServices();
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_0);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_3, ShortcutActivity.class.getName()),
+                R.xml.shortcut_0);
+
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        updatePackageVersion(CALLING_PACKAGE_2, 1);
+        updatePackageVersion(CALLING_PACKAGE_3, 1);
+
+        initService();
+        mService.handleUnlockUser(USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
+                    assertAllDisabled(mManager.getPinnedShortcuts())))),
+                    "ms3");
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
+                    assertAllDisabled(mManager.getPinnedShortcuts())))),
+                    "ms2");
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllNotManifest(
+                    assertAllDisabled(mManager.getPinnedShortcuts())))),
+                    "ms1");
+        });
+
+        // Make sure we don't have ShortcutPackage for packages that don't have shortcuts.
+        assertNull(mService.getPackageShortcutForTest(CALLING_PACKAGE_4, USER_0));
+        assertNull(mService.getPackageShortcutForTest(LAUNCHER_1, USER_0));
+    }
+
+
+    public void testManifestShortcut_publishOnBroadcast() {
+        // First, no packages are installed.
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+        uninstallPackage(USER_0, CALLING_PACKAGE_3);
+        uninstallPackage(USER_0, CALLING_PACKAGE_4);
+        uninstallPackage(USER_10, CALLING_PACKAGE_1);
+        uninstallPackage(USER_10, CALLING_PACKAGE_2);
+        uninstallPackage(USER_10, CALLING_PACKAGE_3);
+        uninstallPackage(USER_10, CALLING_PACKAGE_4);
+
+        mService.handleUnlockUser(USER_0);
+        mService.handleUnlockUser(USER_10);
+
+        // Originally no manifest shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Package 1 updated, with manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Package 2 updated, with manifest shortcuts.
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+        updatePackageVersion(CALLING_PACKAGE_2, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // Package 2 updated, with less manifest shortcuts.
+        // This time we use updatePackageLastUpdateTime() instead of updatePackageVersion().
+
+        dumpsysOnLogcat("Before pinning");
+
+        // Also pin some.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, list("ms2", "ms3"), HANDLE_USER_0);
+        });
+
+        dumpsysOnLogcat("After pinning");
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(
+                    mManager.getPinnedShortcuts())),
+                    "ms2", "ms3");
+            // ms3 is no longer in manifest, so should be disabled.
+            // but ms1 and ms2 should be enabled.
+            assertAllEnabled(list(getCallerShortcut("ms1")));
+            assertAllEnabled(list(getCallerShortcut("ms2")));
+            assertAllDisabled(list(getCallerShortcut("ms3")));
+        });
+
+        // Package 2 on user 10 has no shortcuts yet.
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+        // Send PACKAGE_ADD broadcast to have Package 2 on user-10 publish manifest shortcuts.
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_2, USER_10));
+
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertEmpty(mManager.getPinnedShortcuts());
+        });
+
+        // But it shouldn't affect user-0.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+            assertShortcutIds(assertAllImmutable(assertAllPinned(
+                    mManager.getPinnedShortcuts())),
+                    "ms2", "ms3");
+            assertAllEnabled(list(getCallerShortcut("ms1")));
+            assertAllEnabled(list(getCallerShortcut("ms2")));
+            assertAllDisabled(list(getCallerShortcut("ms3")));
+        });
+
+        // Package 2 now has no manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_2, ShortcutActivity.class.getName()),
+                R.xml.shortcut_0);
+        updatePackageLastUpdateTime(CALLING_PACKAGE_2, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_2, USER_0));
+
+        // No manifest shortcuts, and pinned ones are disabled.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertShortcutIds(assertAllImmutable(assertAllPinned(assertAllDisabled(
+                    mManager.getPinnedShortcuts()))),
+                    "ms2", "ms3");
+        });
+    }
+
+    public void testManifestShortcuts_missingMandatoryFields() {
+        // Start with no apps installed.
+        uninstallPackage(USER_0, CALLING_PACKAGE_1);
+        uninstallPackage(USER_0, CALLING_PACKAGE_2);
+        uninstallPackage(USER_0, CALLING_PACKAGE_3);
+        uninstallPackage(USER_0, CALLING_PACKAGE_4);
+
+        mService.handleUnlockUser(USER_0);
+
+        // Make sure no manifest shortcuts.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+        });
+
+        // Package 1 updated, which has one valid manifest shortcut and one invalid.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_error_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "x1");
+        });
+
+        // Package 1 updated, which has one valid manifest shortcut and one invalid.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_error_2);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "x2");
+        });
+
+        // Package 1 updated, which has one valid manifest shortcut and one invalid.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_error_3);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "x3");
+        });
+    }
+
+    public void testManifestShortcuts_checkAllFields() {
+        mService.handleUnlockUser(USER_0);
+
+        // Package 1 updated, which has one valid manifest shortcut and one invalid.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2", "ms3", "ms4", "ms5");
+
+            // check first shortcut.
+            ShortcutInfo si = getCallerShortcut("ms1");
+
+            assertEquals("ms1", si.getId());
+            assertEquals(R.drawable.icon1, si.getIconResourceId());
+            assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    si.getActivity());
+            assertEquals(R.string.shortcut_title1, si.getTitleResId());
+            assertEquals(R.string.shortcut_text1, si.getTextResId());
+            assertEquals(R.string.shortcut_disabled_message1, si.getDisabledMessageResourceId());
+            assertEquals(set("android.shortcut.conversation", "android.shortcut.media"),
+                    si.getCategories());
+            assertEquals("action1", si.getIntent().getAction());
+            assertEquals(Uri.parse("http://a.b.c/1"), si.getIntent().getData());
+            assertEquals(0, si.getRank());
+
+            // check another
+            si = getCallerShortcut("ms2");
+
+            assertEquals("ms2", si.getId());
+            assertEquals(R.drawable.icon2, si.getIconResourceId());
+            assertEquals(R.string.shortcut_title2, si.getTitleResId());
+            assertEquals(R.string.shortcut_text2, si.getTextResId());
+            assertEquals(R.string.shortcut_disabled_message2, si.getDisabledMessageResourceId());
+            assertEquals(set("android.shortcut.conversation"), si.getCategories());
+            assertEquals("action2", si.getIntent().getAction());
+            assertEquals(null, si.getIntent().getData());
+            assertEquals(1, si.getRank());
+
+            // check another
+            si = getCallerShortcut("ms3");
+
+            assertEquals("ms3", si.getId());
+            assertEquals(0, si.getIconResourceId());
+            assertEquals(R.string.shortcut_title1, si.getTitleResId());
+            assertEquals(0, si.getTextResId());
+            assertEquals(0, si.getDisabledMessageResourceId());
+            assertEquals(null, si.getCategories());
+            assertEquals("android.intent.action.VIEW", si.getIntent().getAction());
+            assertEquals(null, si.getIntent().getData());
+            assertEquals(2, si.getRank());
+        });
+    }
+
+    public void testManifestShortcuts_updateAndDisabled_notPinned() {
+        mService.handleUnlockUser(USER_0);
+
+        // First, just publish a manifest shortcut.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+
+            // Make sure there's no other dangling shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "ms1");
+        });
+
+        // Now version up, the manifest shortcut is disabled now.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1_disable);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Because shortcut 1 wasn't pinned, it'll just go away.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertEmpty(mManager.getPinnedShortcuts());
+
+            // Make sure there's no other dangling shortcuts.
+            assertEmpty(getCallerShortcuts());
+        });
+    }
+
+    public void testManifestShortcuts_updateAndDisabled_pinned() {
+        mService.handleUnlockUser(USER_0);
+
+        // First, just publish a manifest shortcut.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Only the valid one is published.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+            assertEmpty(mManager.getPinnedShortcuts());
+
+            // Make sure there's no other dangling shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "ms1");
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms1"), HANDLE_USER_0);
+        });
+
+        // Now upgrade, the manifest shortcut is disabled now.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1_disable);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        // Because shortcut 1 was pinned, it'll still exist as pinned, but disabled.
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEmpty(mManager.getManifestShortcuts());
+            assertShortcutIds(assertAllNotManifest(assertAllImmutable(assertAllDisabled(
+                    mManager.getPinnedShortcuts()))),
+                    "ms1");
+
+            // Make sure the fields are updated.
+            ShortcutInfo si = getCallerShortcut("ms1");
+
+            assertEquals("ms1", si.getId());
+            assertEquals(R.drawable.icon2, si.getIconResourceId());
+            assertEquals(R.string.shortcut_title2, si.getTitleResId());
+            assertEquals(R.string.shortcut_text2, si.getTextResId());
+            assertEquals(R.string.shortcut_disabled_message2, si.getDisabledMessageResourceId());
+            assertEquals(Intent.ACTION_VIEW, si.getIntent().getAction());
+
+            // Make sure there's no other dangling shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "ms1");
+        });
+    }
+
+    public void testManifestShortcuts_duplicateInSingleActivity() {
+        mService.handleUnlockUser(USER_0);
+
+        // The XML has two shortcuts with the same ID.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2_duplicate);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1");
+
+            // Make sure the first one has survived.  (the second one has a different title.)
+            ShortcutInfo si = getCallerShortcut("ms1");
+            assertEquals(R.string.shortcut_title1, si.getTitleResId());
+
+            // Make sure there's no other dangling shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "ms1");
+        });
+    }
+
+    public void testManifestShortcuts_duplicateInTwoActivities() {
+        mService.handleUnlockUser(USER_0);
+
+        // ShortcutActivity has shortcut ms1
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+
+        // ShortcutActivity2 has two shortcuts, ms1 and ms2.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
+                R.xml.shortcut_2);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllManifest(assertAllImmutable(assertAllEnabled(
+                    mManager.getManifestShortcuts()))),
+                    "ms1", "ms2");
+
+            // ms1 should belong to ShortcutActivity.
+            ShortcutInfo si = getCallerShortcut("ms1");
+            assertEquals(R.string.shortcut_title1, si.getTitleResId());
+            assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    si.getActivity());
+
+            // ms2 should belong to ShortcutActivity*2*.
+            si = getCallerShortcut("ms2");
+            assertEquals(R.string.shortcut_title2, si.getTitleResId());
+            assertEquals(new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
+                    si.getActivity());
+
+            // Make sure there's no other dangling shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "ms1", "ms2");
+        });
+    }
+
+    /**
+     * Manifest shortcuts cannot override shortcuts that were published via the APIs.
+     */
+    public void testManifestShortcuts_cannotOverrideNonManifest() {
+        mService.handleUnlockUser(USER_0);
+
+        // Create a non-pinned dynamic shortcut and a non-dynamic pinned shortcut.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.setDynamicShortcuts(list(
+                    makeShortcut("ms1", "title1",
+                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    /* icon */ null, new Intent("action1"), /* rank */ 0),
+                    makeShortcut("ms2", "title2",
+                            new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    /* icon */ null, new Intent("action1"), /* rank */ 0)));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.removeDynamicShortcuts(list("ms2"));
+
+            assertShortcutIds(mManager.getDynamicShortcuts(), "ms1");
+            assertShortcutIds(mManager.getPinnedShortcuts(), "ms2");
+            assertEmpty(mManager.getManifestShortcuts());
+        });
+
+        // Then update the app with 5 manifest shortcuts.
+        // Make sure "ms1" and "ms2" won't be replaced.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllNotManifest(mManager.getDynamicShortcuts()), "ms1");
+            assertShortcutIds(assertAllNotManifest(mManager.getPinnedShortcuts()), "ms2");
+            assertShortcutIds(assertAllManifest(mManager.getManifestShortcuts()),
+                    "ms3", "ms4", "ms5");
+
+            // ms1 and ms2 shouold keep the original title.
+            ShortcutInfo si = getCallerShortcut("ms1");
+            assertEquals("title1", si.getTitle());
+
+            si = getCallerShortcut("ms2");
+            assertEquals("title2", si.getTitle());
+        });
+    }
+
+    protected void checkManifestShortcuts_immutable_verify() {
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertShortcutIds(assertAllNotManifest(assertAllEnabled(
+                    mManager.getDynamicShortcuts())),
+                    "s1");
+            assertShortcutIds(assertAllManifest(assertAllEnabled(
+                    mManager.getManifestShortcuts())),
+                    "ms1");
+            assertShortcutIds(assertAllNotManifest(assertAllDisabled(
+                    mManager.getPinnedShortcuts())),
+                    "ms2");
+
+            assertEquals("t1", getCallerShortcut("s1").getTitle());
+
+            // Make sure there are no other shortcuts.
+            assertShortcutIds(getCallerShortcuts(), "s1", "ms1", "ms2");
+        });
+    }
+
+    /**
+     * Make sure the APIs won't work on manifest shortcuts.
+     */
+    public void testManifestShortcuts_immutable() {
+        mService.handleUnlockUser(USER_0);
+
+        // Create a non-pinned manifest shortcut, a pinned shortcut that was originally
+        // a manifest shortcut, as well as a dynamic shortcut.
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_2);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("ms2"), HANDLE_USER_0);
+        });
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            mManager.addDynamicShortcuts(list(makeShortcutWithTitle("s1", "t1")));
+        });
+
+        checkManifestShortcuts_immutable_verify();
+
+        // Note that even though the first argument is not immutable and only the second one
+        // is immutable, the first argument should not be executed either.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.setDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1")));
+            });
+            assertCannotUpdateImmutable(() -> {
+                mManager.setDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms2")));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.addDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms1")));
+            });
+            assertCannotUpdateImmutable(() -> {
+                mManager.addDynamicShortcuts(list(makeShortcut("xx"), makeShortcut("ms2")));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.updateShortcuts(list(makeShortcut("s1"), makeShortcut("ms1")));
+            });
+            assertCannotUpdateImmutable(() -> {
+                mManager.updateShortcuts(list(makeShortcut("s1"), makeShortcut("ms2")));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.removeDynamicShortcuts(list("s1", "ms1"));
+            });
+            assertCannotUpdateImmutable(() -> {
+                mManager.removeDynamicShortcuts(list("s2", "ms2"));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.disableShortcuts(list("s1", "ms1"));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertCannotUpdateImmutable(() -> {
+                mManager.enableShortcuts(list("s1", "ms2"));
+            });
+        });
+        checkManifestShortcuts_immutable_verify();
+    }
+
+
+    /**
+     * Make sure the APIs won't work on manifest shortcuts.
+     */
+    public void testManifestShortcuts_tooMany() {
+        // Change the max number of shortcuts.
+        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
+
+        mService.handleUnlockUser(USER_0);
+
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_5);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            // Only the first 3 should be published.
+            assertShortcutIds(mManager.getManifestShortcuts(), "ms1", "ms2", "ms3");
+        });
+    }
+
+    public void testMaxShortcutCount_set() {
+        // Change the max number of shortcuts.
+        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
+            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
+            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
+            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
+            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
+            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
+            final ShortcutInfo s1_5 = makeShortcutWithActivity("s15", a1);
+            final ShortcutInfo s1_6 = makeShortcutWithActivity("s16", a1);
+            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
+            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
+            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
+            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
+
+            // 3 shortcuts for 2 activities -> okay
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            mManager.removeAllDynamicShortcuts();
+
+            // 4 shortcut for activity 1 -> too many.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s1_4, s2_1, s2_2, s2_3));
+            });
+            assertEmpty(mManager.getDynamicShortcuts());
+
+            // 4 shortcut for activity 2 -> too many.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3, s2_4));
+            });
+            assertEmpty(mManager.getDynamicShortcuts());
+
+            // First, set 3.  Then set 4, which should be ignored.
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13");
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.setDynamicShortcuts(list(s2_1, s2_2, s2_3, s2_4));
+            });
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13");
+
+            // Set will remove the old dynamic set, unlike add, so the following should pass.
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13");
+            mManager.setDynamicShortcuts(list(s1_4, s1_5, s1_6));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s14", "s15", "s16");
+
+            // Now, test with 2 manifest shortcuts.
+            mManager.removeAllDynamicShortcuts();
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_2);
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+            assertEquals(2, mManager.getManifestShortcuts().size());
+
+            // Setting 1 to activity 1 will work.
+            mManager.setDynamicShortcuts(list(s1_1, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s21", "s22", "s23");
+            assertEquals(2, mManager.getManifestShortcuts().size());
+
+            // But setting 2 will not.
+            mManager.removeAllDynamicShortcuts();
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.setDynamicShortcuts(list(s1_1, s1_2, s2_1, s2_2, s2_3));
+            });
+            assertEmpty(mManager.getDynamicShortcuts());
+            assertEquals(2, mManager.getManifestShortcuts().size());
+        });
+    }
+
+    public void testMaxShortcutCount_add() {
+        // Change the max number of shortcuts.
+        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
+            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
+            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
+            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
+            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
+            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
+            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
+            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
+            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
+            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
+
+            // 3 shortcuts for 2 activities -> okay
+            mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            mManager.removeAllDynamicShortcuts();
+
+            // 4 shortcut for activity 1 -> too many.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s1_4, s2_1, s2_2, s2_3));
+            });
+            assertEmpty(mManager.getDynamicShortcuts());
+
+            // 4 shortcut for activity 2 -> too many.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.addDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3, s2_4));
+            });
+            assertEmpty(mManager.getDynamicShortcuts());
+
+            // First, set 3.  Then add 1 more, which should be ignored.
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13");
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.addDynamicShortcuts(list(s1_4, s2_1));
+            });
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13");
+
+            // Update existing one, which should work.
+            mManager.addDynamicShortcuts(list(makeShortcutWithActivityAndTitle(
+                    "s11", a1, "xxx"), s2_1));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21");
+            assertEquals("xxx", getCallerShortcut("s11").getTitle());
+
+            // Make sure pinned shortcuts won't affect.
+            // - Pin s11 - s13, and remove all dynamic.
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"),
+                        HANDLE_USER_0);
+            });
+            mManager.removeAllDynamicShortcuts();
+
+            assertEmpty(mManager.getDynamicShortcuts());
+            assertShortcutIds(mManager.getPinnedShortcuts(),
+                    "s11", "s12", "s13");
+
+            // Then add dynamic.
+            mManager.addDynamicShortcuts(list(s1_4, s2_1, s2_2, s2_3));
+
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s14", "s21", "s22", "s23");
+            assertShortcutIds(mManager.getPinnedShortcuts(),
+                    "s11", "s12", "s13");
+
+            // Adding "s11" and "s12" back, should work
+            mManager.addDynamicShortcuts(list(s1_1, s1_2));
+
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s14", "s11", "s12", "s21", "s22", "s23");
+            assertShortcutIds(mManager.getPinnedShortcuts(),
+                    "s11", "s12", "s13");
+
+            // Adding back s13 doesn't work.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.addDynamicShortcuts(list(s1_3));
+            });
+
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
+                    "s11", "s12", "s14");
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
+                    "s21", "s22", "s23");
+
+            // Now swap the activities.
+            mManager.updateShortcuts(list(
+                    makeShortcutWithActivity("s11", a2),
+                    makeShortcutWithActivity("s21", a1)));
+
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
+                    "s21", "s12", "s14");
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
+                    "s11", "s22", "s23");
+
+            // Now, test with 2 manifest shortcuts.
+            mManager.removeAllDynamicShortcuts();
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_2);
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+            assertEquals(2, mManager.getManifestShortcuts().size());
+
+            // Adding one shortcut to activity 1 works fine.
+            mManager.addDynamicShortcuts(list(s1_1, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s21", "s22", "s23");
+            assertEquals(2, mManager.getManifestShortcuts().size());
+
+            // But adding one more doesn't.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.addDynamicShortcuts(list(s1_4, s2_1));
+            });
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s21", "s22", "s23");
+            assertEquals(2, mManager.getManifestShortcuts().size());
+        });
+    }
+
+    public void testMaxShortcutCount_update() {
+        // Change the max number of shortcuts.
+        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
+            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
+            final ShortcutInfo s1_1 = makeShortcutWithActivity("s11", a1);
+            final ShortcutInfo s1_2 = makeShortcutWithActivity("s12", a1);
+            final ShortcutInfo s1_3 = makeShortcutWithActivity("s13", a1);
+            final ShortcutInfo s1_4 = makeShortcutWithActivity("s14", a1);
+            final ShortcutInfo s1_5 = makeShortcutWithActivity("s15", a1);
+            final ShortcutInfo s2_1 = makeShortcutWithActivity("s21", a2);
+            final ShortcutInfo s2_2 = makeShortcutWithActivity("s22", a2);
+            final ShortcutInfo s2_3 = makeShortcutWithActivity("s23", a2);
+            final ShortcutInfo s2_4 = makeShortcutWithActivity("s24", a2);
+
+            // 3 shortcuts for 2 activities -> okay
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            // Trying to move s11 from a1 to a2 should fail.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.updateShortcuts(list(makeShortcutWithActivity("s11", a2)));
+            });
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            // Trying to move s21 from a2 to a1 should also fail.
+            assertDynamicShortcutCountExceeded(() -> {
+                mManager.updateShortcuts(list(makeShortcutWithActivity("s21", a1)));
+            });
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            // But, if we do these two at the same time, it should work.
+            mManager.updateShortcuts(list(
+                    makeShortcutWithActivity("s11", a2),
+                    makeShortcutWithActivity("s21", a1)));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
+                    "s21", "s12", "s13");
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
+                    "s11", "s22", "s23");
+
+            // Then reset.
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s11", "s12", "s13", "s21", "s22", "s23");
+
+            // Pin some to have more shortcuts for a1.
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s13"),
+                        HANDLE_USER_0);
+            });
+            mManager.setDynamicShortcuts(list(s1_4, s1_5, s2_1, s2_2, s2_3));
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s14", "s15", "s21", "s22", "s23");
+            assertShortcutIds(mManager.getPinnedShortcuts(),
+                    "s11", "s12", "s13");
+
+            // a1 already has 2 dynamic shortcuts (and 3 pinned shortcuts that used to belong on it)
+            // But that doesn't matter for update -- the following should still work.
+            mManager.updateShortcuts(list(
+                    makeShortcutWithActivityAndTitle("s11", a1, "xxx1"),
+                    makeShortcutWithActivityAndTitle("s12", a1, "xxx2"),
+                    makeShortcutWithActivityAndTitle("s13", a1, "xxx3"),
+                    makeShortcutWithActivityAndTitle("s14", a1, "xxx4"),
+                    makeShortcutWithActivityAndTitle("s15", a1, "xxx5")));
+            // All the shortcuts should still exist they all belong on same activities,
+            // with the updated titles.
+            assertShortcutIds(mManager.getDynamicShortcuts(),
+                    "s14", "s15", "s21", "s22", "s23");
+            assertShortcutIds(mManager.getPinnedShortcuts(),
+                    "s11", "s12", "s13");
+
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a1),
+                    "s14", "s15");
+            assertShortcutIds(filterByActivity(mManager.getDynamicShortcuts(), a2),
+                    "s21", "s22", "s23");
+
+            assertEquals("xxx1", getCallerShortcut("s11").getTitle());
+            assertEquals("xxx2", getCallerShortcut("s12").getTitle());
+            assertEquals("xxx3", getCallerShortcut("s13").getTitle());
+            assertEquals("xxx4", getCallerShortcut("s14").getTitle());
+            assertEquals("xxx5", getCallerShortcut("s15").getTitle());
+        });
+    }
+
+    public void testShortcutsPushedOutByManifest() {
+        // Change the max number of shortcuts.
+        mService.updateConfigurationLocked(ConfigConstants.KEY_MAX_SHORTCUTS + "=3");
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            final ComponentName a1 = new ComponentName(mClientContext, ShortcutActivity.class);
+            final ComponentName a2 = new ComponentName(mClientContext, ShortcutActivity2.class);
+            final ShortcutInfo s1_1 = makeShortcutWithActivityAndRank("s11", a1, 4);
+            final ShortcutInfo s1_2 = makeShortcutWithActivityAndRank("s12", a1, 3);
+            final ShortcutInfo s1_3 = makeShortcutWithActivityAndRank("s13", a1, 2);
+            final ShortcutInfo s1_4 = makeShortcutWithActivityAndRank("s14", a1, 1);
+            final ShortcutInfo s1_5 = makeShortcutWithActivityAndRank("s15", a1, 0);
+            final ShortcutInfo s2_1 = makeShortcutWithActivityAndRank("s21", a2, 0);
+            final ShortcutInfo s2_2 = makeShortcutWithActivityAndRank("s22", a2, 1);
+            final ShortcutInfo s2_3 = makeShortcutWithActivityAndRank("s23", a2, 2);
+            final ShortcutInfo s2_4 = makeShortcutWithActivityAndRank("s24", a2, 3);
+            final ShortcutInfo s2_5 = makeShortcutWithActivityAndRank("s25", a2, 4);
+
+            // Initial state.
+            mManager.setDynamicShortcuts(list(s1_1, s1_2, s1_3, s2_1, s2_2, s2_3));
+            runWithCaller(LAUNCHER_1, USER_0, () -> {
+                mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s11", "s12", "s21", "s22"),
+                        HANDLE_USER_0);
+            });
+            mManager.setDynamicShortcuts(list(s1_2, s1_3, s1_4, s2_2, s2_3, s2_4));
+            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
+                    "s12", "s13", "s14",
+                    "s22", "s23", "s24");
+            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
+                    "s11", "s12",
+                    "s21", "s22");
+
+            // Add 1 manifest shortcut to a1.
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_1);
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+            assertEquals(1, mManager.getManifestShortcuts().size());
+
+            // s12 removed.
+            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
+                    "s13", "s14",
+                    "s22", "s23", "s24");
+            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
+                    "s11", "s12",
+                    "s21", "s22");
+
+            // Add more manifest shortcuts.
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_2);
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
+                    R.xml.shortcut_1_alt);
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+            assertEquals(3, mManager.getManifestShortcuts().size());
+
+            // Note the ones with the highest rank values (== least important) will be removed.
+            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
+                    "s14",
+                    "s22", "s23");
+            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
+                    "s11", "s12",
+                    "s21", "s22");
+
+            // Add more manifest shortcuts.
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_2);
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
+                    R.xml.shortcut_5_alt); // manifest has 5, but max is 3, so a2 will have 3.
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+            assertEquals(5, mManager.getManifestShortcuts().size());
+
+            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
+                    "s14" // a1 has 1 dynamic
+            ); // a2 has no dynamic
+            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
+                    "s11", "s12",
+                    "s21", "s22");
+
+            // Update, no manifest shortucts.  This doesn't affect anything.
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                    R.xml.shortcut_0);
+            addManifestShortcutResource(
+                    new ComponentName(CALLING_PACKAGE_1, ShortcutActivity2.class.getName()),
+                    R.xml.shortcut_0);
+            updatePackageVersion(CALLING_PACKAGE_1, 1);
+            mService.mPackageMonitor.onReceive(getTestContext(),
+                    genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+            assertEquals(0, mManager.getManifestShortcuts().size());
+
+            assertShortcutIds(assertAllEnabled(mManager.getDynamicShortcuts()),
+                    "s14");
+            assertShortcutIds(assertAllEnabled(mManager.getPinnedShortcuts()),
+                    "s11", "s12",
+                    "s21", "s22");
+        });
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
new file mode 100644
index 0000000..1702ca4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -0,0 +1,1470 @@
+/*
+ * 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.pm;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.parceled;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.set;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.Manifest.permission;
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ShortcutInfo;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Icon;
+import android.os.PersistableBundle;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.frameworks.servicestests.R;
+import com.android.server.SystemService;
+
+/**
+ * Tests for ShortcutService and ShortcutManager.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest2 \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+public class ShortcutManagerTest2 extends BaseShortcutManagerTest {
+    // ShortcutInfo tests
+
+    public void testShortcutInfoMissingMandatoryFields() {
+        assertExpectException(
+                IllegalArgumentException.class,
+                "ID must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).build());
+        assertExpectException(
+                NullPointerException.class,
+                "Intent action must be set",
+                () -> new ShortcutInfo.Builder(getTestContext()).setIntent(new Intent()));
+        assertExpectException(
+                NullPointerException.class,
+                "activity must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
+                        .enforceMandatoryFields());
+        assertExpectException(
+                IllegalArgumentException.class,
+                "title must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id")
+                        .setActivity(
+                                new ComponentName(getTestContext().getPackageName(), "s"))
+                        .build()
+                        .enforceMandatoryFields());
+        assertExpectException(
+                NullPointerException.class,
+                "Intent must be provided",
+                () -> new ShortcutInfo.Builder(getTestContext()).setId("id")
+                        .setActivity(
+                                new ComponentName(getTestContext().getPackageName(), "s"))
+                        .setTitle("x").build()
+                        .enforceMandatoryFields());
+    }
+
+    public void testShortcutInfoParcel() {
+        setCaller(CALLING_PACKAGE_1, USER_10);
+        ShortcutInfo si = parceled(new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setTitle("title")
+                .setIntent(makeIntent("action", ShortcutActivity.class))
+                .build());
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals(USER_10, si.getUserId());
+        assertEquals(HANDLE_USER_10, si.getUserHandle());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals("action", si.getIntent().getAction());
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+
+        si = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitle("title")
+                .setText("text")
+                .setDisabledMessage("dismes")
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        si.addFlags(ShortcutInfo.FLAG_PINNED);
+        si.setBitmapPath("abc");
+        si.setIconResourceId(456);
+
+        si = parceled(si);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(123, si.getIcon().getResId());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoParcel_resId() {
+        setCaller(CALLING_PACKAGE_1, USER_10);
+        ShortcutInfo si;
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+
+        si = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitleResId(10)
+                .setTextResId(11)
+                .setDisabledMessageResId(12)
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        si.addFlags(ShortcutInfo.FLAG_PINNED);
+        si.setBitmapPath("abc");
+        si.setIconResourceId(456);
+
+        si = parceled(si);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(123, si.getIcon().getResId());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoClone() {
+        setCaller(CALLING_PACKAGE_1, USER_11);
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitle("title")
+                .setText("text")
+                .setDisabledMessage("dismes")
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+        assertEquals(USER_11, si.getUserId());
+        assertEquals(HANDLE_USER_11, si.getUserHandle());
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(123, si.getIcon().getResId());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals(null, si.getIntent());
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(null, si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals(null, si.getTitle());
+        assertEquals(null, si.getText());
+        assertEquals(null, si.getDisabledMessage());
+        assertEquals(null, si.getCategories());
+        assertEquals(null, si.getIntent());
+        assertEquals(0, si.getRank());
+        assertEquals(null, si.getExtras());
+
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoClone_resId() {
+        setCaller(CALLING_PACKAGE_1, USER_11);
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitleResId(10)
+                .setTextResId(11)
+                .setDisabledMessageResId(12)
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+        assertEquals(USER_11, si.getUserId());
+        assertEquals(HANDLE_USER_11, si.getUserHandle());
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(123, si.getIcon().getResId());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals("abc", si.getBitmapPath());
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(new ComponentName("a", "b"), si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals(null, si.getIntent());
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+        assertEquals(mClientContext.getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(null, si.getActivity());
+        assertEquals(null, si.getIcon());
+        assertEquals(0, si.getTitleResId());
+        assertEquals(0, si.getTextResId());
+        assertEquals(0, si.getDisabledMessageResourceId());
+        assertEquals(null, si.getCategories());
+        assertEquals(null, si.getIntent());
+        assertEquals(0, si.getRank());
+        assertEquals(null, si.getExtras());
+
+        assertEquals(ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_KEY_FIELDS_ONLY, si.getFlags());
+        assertEquals(null, si.getBitmapPath());
+
+        assertEquals(456, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoClone_minimum() {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setTitle("title")
+                .setIntent(makeIntent("action", ShortcutActivity.class))
+                .build();
+        ShortcutInfo si = sorig.clone(/* clone flags*/ 0);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals(null, si.getCategories());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_CREATOR);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals(null, si.getCategories());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals("title", si.getTitle());
+        assertEquals(null, si.getIntent());
+        assertEquals(null, si.getCategories());
+
+        si = sorig.clone(ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO);
+
+        assertEquals(getTestContext().getPackageName(), si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(null, si.getTitle());
+        assertEquals(null, si.getIntent());
+        assertEquals(null, si.getCategories());
+    }
+
+    public void testShortcutInfoCopyNonNullFieldsFrom() throws InterruptedException {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitle("title")
+                .setText("text")
+                .setDisabledMessage("dismes")
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si;
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setActivity(new ComponentName("x", "y")).build());
+        assertEquals("text", si.getText());
+        assertEquals(new ComponentName("x", "y"), si.getActivity());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
+        assertEquals("text", si.getText());
+        assertEquals(456, si.getIcon().getResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+        assertEquals("text", si.getText());
+        assertEquals("xyz", si.getTitle());
+        assertEquals(0, si.getTitleResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitleResId(123).build());
+        assertEquals("text", si.getText());
+        assertEquals(null, si.getTitle());
+        assertEquals(123, si.getTitleResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setText("xxx").build());
+        assertEquals(123, si.getRank());
+        assertEquals("xxx", si.getText());
+        assertEquals(0, si.getTextResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTextResId(1111).build());
+        assertEquals(123, si.getRank());
+        assertEquals(null, si.getText());
+        assertEquals(1111, si.getTextResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setDisabledMessage("xxx").build());
+        assertEquals(123, si.getRank());
+        assertEquals("xxx", si.getDisabledMessage());
+        assertEquals(0, si.getDisabledMessageResourceId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setDisabledMessageResId(11111).build());
+        assertEquals(123, si.getRank());
+        assertEquals(null, si.getDisabledMessage());
+        assertEquals(11111, si.getDisabledMessageResourceId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setCategories(set()).build());
+        assertEquals("text", si.getText());
+        assertEquals(set(), si.getCategories());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setCategories(set("x")).build());
+        assertEquals("text", si.getText());
+        assertEquals(set("x"), si.getCategories());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+        assertEquals("text", si.getText());
+        assertEquals("action2", si.getIntent().getAction());
+        assertEquals(null, si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+        assertEquals("text", si.getText());
+        assertEquals("action3", si.getIntent().getAction());
+        assertEquals("x", si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setRank(999).build());
+        assertEquals("text", si.getText());
+        assertEquals(999, si.getRank());
+
+
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("x", 99);
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setExtras(pb2).build());
+        assertEquals("text", si.getText());
+        assertEquals(99, si.getExtras().getInt("x"));
+
+        // Make sure the timestamp gets updated too.
+
+        final long timestamp = si.getLastChangedTimestamp();
+        Thread.sleep(2);
+
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+
+        assertTrue(si.getLastChangedTimestamp() > timestamp);
+    }
+
+    public void testShortcutInfoCopyNonNullFieldsFrom_resId() throws InterruptedException {
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(getTestContext())
+                .setId("id")
+                .setActivity(new ComponentName("a", "b"))
+                .setIcon(Icon.createWithResource(mClientContext, 123))
+                .setTitleResId(10)
+                .setTextResId(11)
+                .setDisabledMessageResId(12)
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+        sorig.addFlags(ShortcutInfo.FLAG_PINNED);
+        sorig.setBitmapPath("abc");
+        sorig.setIconResourceId(456);
+
+        ShortcutInfo si;
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setActivity(new ComponentName("x", "y")).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(new ComponentName("x", "y"), si.getActivity());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIcon(Icon.createWithResource(mClientContext, 456)).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(456, si.getIcon().getResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+        assertEquals(11, si.getTextResId());
+        assertEquals("xyz", si.getTitle());
+        assertEquals(0, si.getTitleResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitleResId(123).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(null, si.getTitle());
+        assertEquals(123, si.getTitleResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setText("xxx").build());
+        assertEquals(123, si.getRank());
+        assertEquals("xxx", si.getText());
+        assertEquals(0, si.getTextResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTextResId(1111).build());
+        assertEquals(123, si.getRank());
+        assertEquals(null, si.getText());
+        assertEquals(1111, si.getTextResId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setDisabledMessage("xxx").build());
+        assertEquals(123, si.getRank());
+        assertEquals("xxx", si.getDisabledMessage());
+        assertEquals(0, si.getDisabledMessageResourceId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setDisabledMessageResId(11111).build());
+        assertEquals(123, si.getRank());
+        assertEquals(null, si.getDisabledMessage());
+        assertEquals(11111, si.getDisabledMessageResourceId());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setCategories(set()).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(set(), si.getCategories());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setCategories(set("x")).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(set("x"), si.getCategories());
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action2", ShortcutActivity.class)).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals("action2", si.getIntent().getAction());
+        assertEquals(null, si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setIntent(makeIntent("action3", ShortcutActivity.class, "key", "x")).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals("action3", si.getIntent().getAction());
+        assertEquals("x", si.getIntent().getStringExtra("key"));
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setRank(999).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(999, si.getRank());
+
+
+        PersistableBundle pb2 = new PersistableBundle();
+        pb2.putInt("x", 99);
+
+        si = sorig.clone(/* flags=*/ 0);
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setExtras(pb2).build());
+        assertEquals(11, si.getTextResId());
+        assertEquals(99, si.getExtras().getInt("x"));
+
+        // Make sure the timestamp gets updated too.
+
+        final long timestamp = si.getLastChangedTimestamp();
+        Thread.sleep(2);
+
+        si.copyNonNullFieldsFrom(new ShortcutInfo.Builder(getTestContext()).setId("id")
+                .setTitle("xyz").build());
+
+        assertTrue(si.getLastChangedTimestamp() > timestamp);
+    }
+
+    public void testShortcutInfoSaveAndLoad() throws InterruptedException {
+        setCaller(CALLING_PACKAGE_1, USER_10);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setDisabledMessage("dismes")
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcuts(list(sorig));
+
+        Thread.sleep(2);
+        final long now = System.currentTimeMillis();
+
+        // Save and load.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_10);
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
+
+        assertEquals(USER_10, si.getUserId());
+        assertEquals(HANDLE_USER_10, si.getUserHandle());
+        assertEquals(CALLING_PACKAGE_1, si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+        assertNotNull(si.getBitmapPath()); // Something should be set.
+        assertEquals(0, si.getIconResourceId());
+        assertTrue(si.getLastChangedTimestamp() < now);
+    }
+
+    public void testShortcutInfoSaveAndLoad_resId() throws InterruptedException {
+        setCaller(CALLING_PACKAGE_1, USER_10);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitleResId(10)
+                .setTextResId(11)
+                .setDisabledMessageResId(12)
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcuts(list(sorig));
+
+        Thread.sleep(2);
+        final long now = System.currentTimeMillis();
+
+        // Save and load.
+        mService.saveDirtyInfo();
+        initService();
+        mService.handleUnlockUser(USER_10);
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_10);
+
+        assertEquals(USER_10, si.getUserId());
+        assertEquals(HANDLE_USER_10, si.getUserHandle());
+        assertEquals(CALLING_PACKAGE_1, si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_HAS_ICON_FILE, si.getFlags());
+        assertNotNull(si.getBitmapPath()); // Something should be set.
+        assertEquals(0, si.getIconResourceId());
+        assertTrue(si.getLastChangedTimestamp() < now);
+    }
+
+    public void testShortcutInfoSaveAndLoad_forBackup() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitle("title")
+                .setText("text")
+                .setDisabledMessage("dismes")
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcuts(list(sorig));
+
+        // Dynamic shortcuts won't be backed up, so we need to pin it.
+        setCaller(LAUNCHER_1, USER_0);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+        // Do backup & restore.
+        backupAndRestore();
+
+        mService.handleUnlockUser(USER_0); // Load user-0.
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals("title", si.getTitle());
+        assertEquals("text", si.getText());
+        assertEquals("dismes", si.getDisabledMessage());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertNull(si.getBitmapPath()); // No icon.
+        assertEquals(0, si.getIconResourceId());
+    }
+
+    public void testShortcutInfoSaveAndLoad_forBackup_resId() {
+        setCaller(CALLING_PACKAGE_1, USER_0);
+
+        final Icon bmp32x32 = Icon.createWithBitmap(BitmapFactory.decodeResource(
+                getTestContext().getResources(), R.drawable.black_32x32));
+
+        PersistableBundle pb = new PersistableBundle();
+        pb.putInt("k", 1);
+        ShortcutInfo sorig = new ShortcutInfo.Builder(mClientContext)
+                .setId("id")
+                .setActivity(new ComponentName(mClientContext, ShortcutActivity2.class))
+                .setIcon(bmp32x32)
+                .setTitleResId(10)
+                .setTextResId(11)
+                .setDisabledMessageResId(12)
+                .setCategories(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"))
+                .setIntent(makeIntent("action", ShortcutActivity.class, "key", "val"))
+                .setRank(123)
+                .setExtras(pb)
+                .build();
+
+        mManager.addDynamicShortcuts(list(sorig));
+
+        // Dynamic shortcuts won't be backed up, so we need to pin it.
+        setCaller(LAUNCHER_1, USER_0);
+        mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("id"), HANDLE_USER_0);
+
+        // Do backup & restore.
+        backupAndRestore();
+
+        mService.handleUnlockUser(USER_0); // Load user-0.
+
+        ShortcutInfo si;
+        si = mService.getPackageShortcutForTest(CALLING_PACKAGE_1, "id", USER_0);
+
+        assertEquals(CALLING_PACKAGE_1, si.getPackage());
+        assertEquals("id", si.getId());
+        assertEquals(ShortcutActivity2.class.getName(), si.getActivity().getClassName());
+        assertEquals(null, si.getIcon());
+        assertEquals(10, si.getTitleResId());
+        assertEquals(11, si.getTextResId());
+        assertEquals(12, si.getDisabledMessageResourceId());
+        assertEquals(set(ShortcutInfo.SHORTCUT_CATEGORY_CONVERSATION, "xyz"), si.getCategories());
+        assertEquals("action", si.getIntent().getAction());
+        assertEquals("val", si.getIntent().getStringExtra("key"));
+        assertEquals(123, si.getRank());
+        assertEquals(1, si.getExtras().getInt("k"));
+
+        assertEquals(ShortcutInfo.FLAG_PINNED, si.getFlags());
+        assertNull(si.getBitmapPath()); // No icon.
+        assertEquals(0, si.getIconResourceId());
+    }
+
+
+    public void testThrottling() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Reached the max
+
+        mInjectedCurrentTimeMillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Still throttled
+        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Now it should work.
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1))); // fail
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 2, mManager.getRateLimitResetTime());
+
+        // 4 hours later...
+        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 5, mManager.getRateLimitResetTime());
+
+        // Make sure getRemainingCallCount() itself gets reset without calling setDynamicShortcuts().
+        mInjectedCurrentTimeMillis = START_TIME + 8 * INTERVAL;
+        assertEquals(3, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL * 9, mManager.getRateLimitResetTime());
+    }
+
+    public void testThrottling_rewind() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        mInjectedCurrentTimeMillis = 12345; // Clock reset!
+
+        // Since the clock looks invalid, the counter shouldn't have reset.
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Forward again.  Still haven't reset yet.
+        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
+        assertEquals(2, mManager.getRemainingCallCount());
+        assertEquals(START_TIME + INTERVAL, mManager.getRateLimitResetTime());
+
+        // Now rewind -- this will reset the counters.
+        mInjectedCurrentTimeMillis = START_TIME - 100000;
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        // Forward again, should be reset now.
+        mInjectedCurrentTimeMillis += INTERVAL;
+        assertEquals(3, mManager.getRemainingCallCount());
+    }
+
+    public void testThrottling_perPackage() {
+        final ShortcutInfo si1 = makeShortcut("shortcut1");
+
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        // Reached the max
+
+        mInjectedCurrentTimeMillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        // Try from a different caller.
+        mInjectedClientPackage = CALLING_PACKAGE_2;
+        mInjectedCallingUid = CALLING_UID_2;
+
+        // Need to create a new one wit the updated package name.
+        final ShortcutInfo si2 = makeShortcut("shortcut1");
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertEquals(2, mManager.getRemainingCallCount());
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertEquals(1, mManager.getRemainingCallCount());
+
+        // Back to the original caller, still throttled.
+        mInjectedClientPackage = CALLING_PACKAGE_1;
+        mInjectedCallingUid = CALLING_UID_1;
+
+        mInjectedCurrentTimeMillis = START_TIME + INTERVAL - 1;
+        assertEquals(0, mManager.getRemainingCallCount());
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+        assertEquals(0, mManager.getRemainingCallCount());
+
+        // Now it should work.
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeMillis++;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeMillis++;
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedCurrentTimeMillis = START_TIME + 4 * INTERVAL;
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertTrue(mManager.setDynamicShortcuts(list(si1)));
+        assertFalse(mManager.setDynamicShortcuts(list(si1)));
+
+        mInjectedClientPackage = CALLING_PACKAGE_2;
+        mInjectedCallingUid = CALLING_UID_2;
+
+        assertEquals(3, mManager.getRemainingCallCount());
+
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertTrue(mManager.setDynamicShortcuts(list(si2)));
+        assertFalse(mManager.setDynamicShortcuts(list(si2)));
+    }
+
+    public void testThrottling_localeChanges() {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        final long origSequenceNumber = mService.getLocaleChangeSequenceNumber();
+
+        // onSystemLocaleChangedNoLock before boot completed will be ignored.
+        mInternal.onSystemLocaleChangedNoLock();
+        assertEquals(origSequenceNumber, mService.getLocaleChangeSequenceNumber());
+
+        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+        mInternal.onSystemLocaleChangedNoLock();
+        assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+
+        // Note at this point only user-0 is loaded, and the counters are reset for this user,
+        // but it will work for other users too, because we persist when
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+
+        mService.saveDirtyInfo();
+        initService();
+
+        // Make sure the counter is persisted.
+        assertEquals(origSequenceNumber + 1, mService.getLocaleChangeSequenceNumber());
+    }
+
+    public void testThrottling_foreground() throws Exception {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        // We need to update the current time from time to time, since some of the internal checks
+        // rely on the time being correctly incremented.
+        mInjectedCurrentTimeMillis++;
+
+        // First, all packages have less than 3 (== initial value) remaining calls.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mInjectedCurrentTimeMillis++;
+
+        // State changed, but not foreground, so no resetting.
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mInjectedCurrentTimeMillis++;
+
+        // State changed, package1 foreground, reset.
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_1, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+
+        mInjectedCurrentTimeMillis++;
+
+        // Different app comes to foreground briefly, and goes back to background.
+        // Now, make sure package 2's counter is reset, even in this case.
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mInjectedCurrentTimeMillis++;
+
+        // Do the same thing one more time.  This would catch the bug with mixuing up
+        // the current time and the elapsed time.
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            mManager.updateShortcuts(list(makeShortcut("s")));
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        mService.mUidObserver.onUidStateChanged(
+                CALLING_UID_2, ActivityManager.PROCESS_STATE_TOP_SLEEPING);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mInjectedCurrentTimeMillis++;
+
+        // Package 1 on user-10 comes to foreground.
+        // Now, also try calling some APIs and make sure foreground apps don't get throttled.
+        mService.mUidObserver.onUidStateChanged(
+                UserHandle.getUid(USER_10, CALLING_UID_1),
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(0, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(0, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(0, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(0, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(0, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+            mManager.setDynamicShortcuts(list(makeShortcut("s")));
+
+            assertEquals(3, mManager.getRemainingCallCount()); // Still 3!
+        });
+    }
+
+
+    public void testThrottling_resetByInternalCall() throws Exception {
+        prepareCrossProfileDataSet();
+
+        dumpsysOnLogcat("Before save & load");
+
+        mService.saveDirtyInfo();
+        initService();
+
+        // First, all packages have less than 3 (== initial value) remaining calls.
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        // Simulate a call from sys UI.
+        mCallerPermissions.add(permission.RESET_SHORTCUT_MANAGER_THROTTLING);
+        mService.onApplicationActive(CALLING_PACKAGE_1, USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mService.onApplicationActive(CALLING_PACKAGE_3, USER_0);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+
+        mService.onApplicationActive(CALLING_PACKAGE_1, USER_10);
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_4, USER_0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            MoreAsserts.assertNotEqual(3, mManager.getRemainingCallCount());
+        });
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            assertEquals(3, mManager.getRemainingCallCount());
+        });
+    }
+
+    public void testReportShortcutUsed() {
+        runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+            reset(mMockUsageStatsManagerInternal);
+
+            // Report with an nonexistent shortcut.
+            mManager.reportShortcutUsed("s1");
+            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+                    anyString(), anyString(), anyInt());
+
+            // Publish s2, but s1 still doesn't exist.
+            mManager.setDynamicShortcuts(list(makeShortcut("s2")));
+            mManager.reportShortcutUsed("s1");
+            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+                    anyString(), anyString(), anyInt());
+
+            mManager.reportShortcutUsed("s2");
+            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+                    eq(CALLING_PACKAGE_1), eq("s2"), eq(USER_10));
+
+        });
+        runWithCaller(CALLING_PACKAGE_2, USER_10, () -> {
+            // Try with a different package.
+            reset(mMockUsageStatsManagerInternal);
+
+            // Report with an nonexistent shortcut.
+            mManager.reportShortcutUsed("s2");
+            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+                    anyString(), anyString(), anyInt());
+
+            // Publish s2, but s1 still doesn't exist.
+            mManager.setDynamicShortcuts(list(makeShortcut("s3")));
+            mManager.reportShortcutUsed("s2");
+            verify(mMockUsageStatsManagerInternal, times(0)).reportShortcutUsage(
+                    anyString(), anyString(), anyInt());
+
+            mManager.reportShortcutUsed("s3");
+            verify(mMockUsageStatsManagerInternal, times(1)).reportShortcutUsage(
+                    eq(CALLING_PACKAGE_2), eq("s3"), eq(USER_10));
+
+        });
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
index 48a11c5..9f77297 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -23,12 +23,14 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.AtomicFile;
 
 import java.io.File;
 import java.io.IOException;
 import java.util.Arrays;
 
+@SmallTest
 public class UserManagerServiceTest extends AndroidTestCase {
     private static String[] STRING_ARRAY = new String[] {"<tag", "<![CDATA["};
     private File restrictionsFile;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 6c2fcd5..ced4980 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -25,6 +25,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
 
 import com.android.internal.util.ArrayUtils;
 
@@ -33,6 +34,7 @@
 import java.util.List;
 
 /** Test {@link UserManager} functionality. */
+@MediumTest
 public class UserManagerTest extends AndroidTestCase {
     private static final int REMOVE_CHECK_INTERVAL = 500;
     private static final int REMOVE_TIMEOUT = 60 * 1000;
@@ -96,7 +98,7 @@
                     && !user.isPrimary()) {
                 found = true;
                 Bundle restrictions = mUserManager.getUserRestrictions(user.getUserHandle());
-                assertFalse("New user should have DISALLOW_CONFIG_WIFI =false by default",
+                assertTrue("Guest user should have DISALLOW_CONFIG_WIFI=true by default",
                         restrictions.getBoolean(UserManager.DISALLOW_CONFIG_WIFI));
             }
         }
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 5bdf6f7..e2dce853 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -23,6 +23,7 @@
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
 
 /**
  * Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
@@ -35,6 +36,7 @@
      -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
  * </pre>
  */
+@SmallTest
 public class UserRestrictionsUtilsTest extends AndroidTestCase {
     public void testNonNull() {
         Bundle out = UserRestrictionsUtils.nonNull(null);
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
new file mode 100644
index 0000000..701e058
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    mockito-target
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := ShortcutManagerTestUtils
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
new file mode 100644
index 0000000..71878fd
--- /dev/null
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -0,0 +1,614 @@
+/*
+ * 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.pm.shortcutmanagertest;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.BaseBundle;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.mockito.Mockito;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BooleanSupplier;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Common utility methods for ShortcutManager tests.  This is used by both CTS and the unit tests.
+ * Because it's used by CTS too, it can only access the public APIs.
+ */
+public class ShortcutManagerTestUtils {
+    private static final String TAG = "ShortcutManagerUtils";
+
+    private static final boolean ENABLE_DUMPSYS = true; // DO NOT SUBMIT WITH true
+
+    private static final int STANDARD_TIMEOUT_SEC = 5;
+
+    private ShortcutManagerTestUtils() {
+    }
+
+    private static List<String> readAll(ParcelFileDescriptor pfd) {
+        try {
+            try {
+                final ArrayList<String> ret = new ArrayList<>();
+                try (BufferedReader r = new BufferedReader(
+                        new FileReader(pfd.getFileDescriptor()))) {
+                    String line;
+                    while ((line = r.readLine()) != null) {
+                        ret.add(line);
+                    }
+                    r.readLine();
+                }
+                return ret;
+            } finally {
+                pfd.close();
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String concatResult(List<String> result) {
+        final StringBuilder sb = new StringBuilder();
+        for (String s : result) {
+            sb.append(s);
+            sb.append("\n");
+        }
+        return sb.toString();
+    }
+
+    private static List<String> runCommand(Instrumentation instrumentation, String command) {
+        return runCommand(instrumentation, command, null);
+    }
+    private static List<String> runCommand(Instrumentation instrumentation, String command,
+            Predicate<List<String>> resultAsserter) {
+        Log.d(TAG, "Running command: " + command);
+        final List<String> result;
+        try {
+            result = readAll(
+                    instrumentation.getUiAutomation().executeShellCommand(command));
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        if (resultAsserter != null && !resultAsserter.test(result)) {
+            fail("Command '" + command + "' failed, output was:\n" + concatResult(result));
+        }
+        return result;
+    }
+
+    private static void runCommandForNoOutput(Instrumentation instrumentation, String command) {
+        runCommand(instrumentation, command, result -> result.size() == 0);
+    }
+
+    private static List<String> runShortcutCommand(Instrumentation instrumentation, String command,
+            Predicate<List<String>> resultAsserter) {
+        return runCommand(instrumentation, "cmd shortcut " + command, resultAsserter);
+    }
+
+    public static List<String> runShortcutCommandForSuccess(Instrumentation instrumentation,
+            String command) {
+        return runShortcutCommand(instrumentation, command, result -> result.contains("Success"));
+    }
+
+    public static String getDefaultLauncher(Instrumentation instrumentation) {
+        final String PREFIX = "Launcher: ComponentInfo{";
+        final String POSTFIX = "}";
+        final List<String> result = runShortcutCommandForSuccess(
+                instrumentation, "get-default-launcher");
+        for (String s : result) {
+            if (s.startsWith(PREFIX) && s.endsWith(POSTFIX)) {
+                return s.substring(PREFIX.length(), s.length() - POSTFIX.length());
+            }
+        }
+        fail("Default launcher not found");
+        return null;
+    }
+
+    public static void setDefaultLauncher(Instrumentation instrumentation, String component) {
+        runCommandForNoOutput(instrumentation, "cmd package set-home-activity " + component);
+    }
+
+    public static void setDefaultLauncher(Instrumentation instrumentation, Context packageContext) {
+        setDefaultLauncher(instrumentation, packageContext.getPackageName()
+                + "/android.content.pm.cts.shortcutmanager.packages.Launcher");
+    }
+
+    public static void overrideConfig(Instrumentation instrumentation, String config) {
+        runShortcutCommandForSuccess(instrumentation, "override-config " + config);
+    }
+
+    public static void resetConfig(Instrumentation instrumentation) {
+        runShortcutCommandForSuccess(instrumentation, "reset-config");
+    }
+
+    public static void resetThrottling(Instrumentation instrumentation) {
+        runShortcutCommandForSuccess(instrumentation, "reset-throttling");
+    }
+
+    public static void resetAllThrottling(Instrumentation instrumentation) {
+        runShortcutCommandForSuccess(instrumentation, "reset-all-throttling");
+    }
+
+    public static void clearShortcuts(Instrumentation instrumentation, int userId,
+            String packageName) {
+        runShortcutCommandForSuccess(instrumentation, "clear-shortcuts "
+                + " --user " + userId + " " + packageName);
+    }
+
+    public static void dumpsysShortcut(Instrumentation instrumentation) {
+        if (!ENABLE_DUMPSYS) {
+            return;
+        }
+        for (String s : runCommand(instrumentation, "dumpsys shortcut")) {
+            Log.e(TAG, s);
+        }
+    }
+
+    public static Bundle makeBundle(Object... keysAndValues) {
+        assertTrue((keysAndValues.length % 2) == 0);
+
+        if (keysAndValues.length == 0) {
+            return null;
+        }
+        final Bundle ret = new Bundle();
+
+        for (int i = keysAndValues.length - 2; i >= 0; i -= 2) {
+            final String key = keysAndValues[i].toString();
+            final Object value = keysAndValues[i + 1];
+
+            if (value == null) {
+                ret.putString(key, null);
+            } else if (value instanceof Integer) {
+                ret.putInt(key, (Integer) value);
+            } else if (value instanceof String) {
+                ret.putString(key, (String) value);
+            } else if (value instanceof Bundle) {
+                ret.putBundle(key, (Bundle) value);
+            } else {
+                fail("Type not supported yet: " + value.getClass().getName());
+            }
+        }
+        return ret;
+    }
+
+    public static <T> List<T> list(T... array) {
+        return Arrays.asList(array);
+    }
+
+    public static <T> Set<T> hashSet(Set<T> in) {
+        return new HashSet<T>(in);
+    }
+
+    public static <T> Set<T> set(T... values) {
+        return set(v -> v, values);
+    }
+
+    public static <T, V> Set<T> set(Function<V, T> converter, V... values) {
+        return set(converter, Arrays.asList(values));
+    }
+
+    public static <T, V> Set<T> set(Function<V, T> converter, List<V> values) {
+        final HashSet<T> ret = new HashSet<>();
+        for (V v : values) {
+            ret.add(converter.apply(v));
+        }
+        return ret;
+    }
+
+    public static void resetAll(Collection<?> mocks) {
+        for (Object o : mocks) {
+            reset(o);
+        }
+    }
+
+    public static <T> List<T> assertEmpty(List<T> list) {
+        assertEquals(0, list.size());
+        return list;
+    }
+
+    public static List<ShortcutInfo> filterByActivity(List<ShortcutInfo> list,
+            ComponentName activity) {
+        final ArrayList<ShortcutInfo> ret = new ArrayList<>();
+        for (ShortcutInfo si : list) {
+            if (si.getActivity().equals(activity) && (si.isManifestShortcut() || si.isDynamic())) {
+                ret.add(si);
+            }
+        }
+        return ret;
+    }
+
+    public static void assertExpectException(Class<? extends Throwable> expectedExceptionType,
+            String expectedExceptionMessageRegex, Runnable r) {
+        assertExpectException("", expectedExceptionType, expectedExceptionMessageRegex, r);
+    }
+
+    public static void assertCannotUpdateImmutable(Runnable r) {
+        assertExpectException(
+                IllegalArgumentException.class, "may not be manipulated via APIs", r);
+    }
+
+    public static void assertDynamicShortcutCountExceeded(Runnable r) {
+        assertExpectException(IllegalArgumentException.class,
+                "Max number of dynamic shortcuts exceeded", r);
+    }
+
+    public static void assertExpectException(String message,
+            Class<? extends Throwable> expectedExceptionType,
+            String expectedExceptionMessageRegex, Runnable r) {
+        try {
+            r.run();
+            Assert.fail("Expected exception type " + expectedExceptionType.getName()
+                    + " was not thrown (message=" + message + ")");
+        } catch (Throwable e) {
+            Assert.assertTrue(
+                    "Expected exception type was " + expectedExceptionType.getName()
+                            + " but caught " + e + " (message=" + message + ")",
+                    expectedExceptionType.isAssignableFrom(e.getClass()));
+            if (expectedExceptionMessageRegex != null) {
+                MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
+            }
+        }
+    }
+
+    public static List<ShortcutInfo> assertShortcutIds(List<ShortcutInfo> actualShortcuts,
+            String... expectedIds) {
+        final HashSet<String> expected = new HashSet<>(list(expectedIds));
+        final HashSet<String> actual = new HashSet<>();
+        for (ShortcutInfo s : actualShortcuts) {
+            actual.add(s.getId());
+        }
+
+        // Compare the sets.
+        assertEquals(expected, actual);
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllHaveIntents(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNotNull("ID " + s.getId(), s.getIntent());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllNotHaveIntents(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getIntent());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllHaveTitle(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNotNull("ID " + s.getId(), s.getShortLabel());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllNotHaveTitle(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertNull("ID " + s.getId(), s.getShortLabel());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllHaveIconResId(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " not have icon res ID", s.hasIconResource());
+            assertFalse("ID " + s.getId() + " shouldn't have icon FD", s.hasIconFile());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllHaveIconFile(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertFalse("ID " + s.getId() + " shouldn't have icon res ID", s.hasIconResource());
+            assertTrue("ID " + s.getId() + " not have icon FD", s.hasIconFile());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllHaveIcon(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId() + " has no icon ", s.hasIconFile() || s.hasIconResource());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllKeyFieldsOnly(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.hasKeyFieldsOnly());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllNotKeyFieldsOnly(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertFalse("ID " + s.getId(), s.hasKeyFieldsOnly());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllDynamic(List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isDynamic());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllPinned(List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isPinned());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllDynamicOrPinned(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isDynamic() || s.isPinned());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllManifest(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isManifestShortcut());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllNotManifest(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertFalse("ID " + s.getId(), s.isManifestShortcut());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllDisabled(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), !s.isEnabled());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllEnabled(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isEnabled());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllImmutable(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.isImmutable());
+        }
+        return actualShortcuts;
+    }
+
+    public static List<ShortcutInfo> assertAllStringsResolved(
+            List<ShortcutInfo> actualShortcuts) {
+        for (ShortcutInfo s : actualShortcuts) {
+            assertTrue("ID " + s.getId(), s.hasStringResourcesResolved());
+        }
+        return actualShortcuts;
+    }
+
+    public static void assertDynamicOnly(ShortcutInfo si) {
+        assertTrue(si.isDynamic());
+        assertFalse(si.isPinned());
+    }
+
+    public static void assertPinnedOnly(ShortcutInfo si) {
+        assertFalse(si.isDynamic());
+        assertFalse(si.isManifestShortcut());
+        assertTrue(si.isPinned());
+    }
+
+    public static void assertDynamicAndPinned(ShortcutInfo si) {
+        assertTrue(si.isDynamic());
+        assertTrue(si.isPinned());
+    }
+
+    public static void assertBitmapSize(int expectedWidth, int expectedHeight, Bitmap bitmap) {
+        assertEquals("width", expectedWidth, bitmap.getWidth());
+        assertEquals("height", expectedHeight, bitmap.getHeight());
+    }
+
+    public static <T> void assertAllUnique(Collection<T> list) {
+        final Set<Object> set = new HashSet<>();
+        for (T item : list) {
+            if (set.contains(item)) {
+                fail("Duplicate item found: " + item + " (in the list: " + list + ")");
+            }
+            set.add(item);
+        }
+    }
+
+    public static ShortcutInfo findShortcut(List<ShortcutInfo> list, String id) {
+        for (ShortcutInfo si : list) {
+            if (si.getId().equals(id)) {
+                return si;
+            }
+        }
+        fail("Shortcut " + id + " not found in the list");
+        return null;
+    }
+
+    public static Bitmap pfdToBitmap(ParcelFileDescriptor pfd) {
+        assertNotNull(pfd);
+        try {
+            try {
+                return BitmapFactory.decodeFileDescriptor(pfd.getFileDescriptor());
+            } finally {
+                pfd.close();
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static void assertBundleEmpty(BaseBundle b) {
+        assertTrue(b == null || b.size() == 0);
+    }
+
+    public static void assertCallbackNotReceived(LauncherApps.Callback mock) {
+        verify(mock, times(0)).onShortcutsChanged(anyString(), anyList(),
+                any(UserHandle.class));
+    }
+
+    public static void assertCallbackReceived(LauncherApps.Callback mock,
+            UserHandle user, String packageName, String... ids) {
+        verify(mock).onShortcutsChanged(eq(packageName), checkShortcutIds(ids),
+                eq(user));
+    }
+
+    public static boolean checkAssertSuccess(Runnable r) {
+        try {
+            r.run();
+            return true;
+        } catch (AssertionError e) {
+            return false;
+        }
+    }
+
+    public static <T> T checkArgument(Predicate<T> checker, String description,
+            List<T> matchedCaptor) {
+        final Matcher<T> m = new BaseMatcher<T>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) {
+                    return false;
+                }
+                final T value = (T) item;
+                if (!checker.test(value)) {
+                    return false;
+                }
+
+                if (matchedCaptor != null) {
+                    matchedCaptor.add(value);
+                }
+                return true;
+            }
+
+            @Override
+            public void describeTo(Description d) {
+                d.appendText(description);
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
+    public static List<ShortcutInfo> checkShortcutIds(String... ids) {
+        return checkArgument((List<ShortcutInfo> list) -> {
+            final Set<String> actualSet = set(si -> si.getId(), list);
+            return actualSet.equals(set(ids));
+
+        }, "Shortcut IDs=[" + Arrays.toString(ids) + "]", null);
+    }
+
+    public static ShortcutInfo parceled(ShortcutInfo si) {
+        Parcel p = Parcel.obtain();
+        p.writeParcelable(si, 0);
+        p.setDataPosition(0);
+        ShortcutInfo si2 = p.readParcelable(ShortcutManagerTestUtils.class.getClassLoader());
+        p.recycle();
+        return si2;
+    }
+
+    public static List<ShortcutInfo> cloneShortcutList(List<ShortcutInfo> list) {
+        if (list == null) {
+            return null;
+        }
+        final List<ShortcutInfo> ret = new ArrayList<>(list.size());
+        for (ShortcutInfo si : list) {
+            ret.add(parceled(si));
+        }
+
+        return ret;
+    }
+
+    public static void waitUntil(String message, BooleanSupplier condition) {
+        waitUntil(message, condition, STANDARD_TIMEOUT_SEC);
+    }
+
+    public static void waitUntil(String message, BooleanSupplier condition, int timeoutSeconds) {
+        final long timeout = System.currentTimeMillis() + (timeoutSeconds * 1000L);
+        while (System.currentTimeMillis() < timeout) {
+            if (condition.getAsBoolean()) {
+                return;
+            }
+            try {
+                Thread.sleep(100);
+            } catch (InterruptedException e) {
+                throw new RuntimeException(e);
+            }
+        }
+        fail("Timed out for: " + message);
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index ecfeff9..eb3c665 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1412,6 +1412,24 @@
         }
 
         @Override
+        public void reportShortcutUsage(String packageName, String shortcutId, int userId) {
+            if (packageName == null || shortcutId == null) {
+                Slog.w(TAG, "Event reported without a package name or a shortcut ID");
+                return;
+            }
+
+            UsageEvents.Event event = new UsageEvents.Event();
+            event.mPackage = packageName.intern();
+            event.mShortcutId = shortcutId.intern();
+
+            // This will later be converted to system time.
+            event.mTimeStamp = SystemClock.elapsedRealtime();
+
+            event.mEventType = Event.SHORTCUT_INVOCATION;
+            mHandler.obtainMessage(MSG_REPORT_EVENT, userId, 0, event).sendToTarget();
+        }
+
+        @Override
         public void reportContentProviderUsage(String name, String packageName, int userId) {
             SomeArgs args = SomeArgs.obtain();
             args.arg1 = name;
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index c95ff23..03cee9c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -51,6 +51,7 @@
     private static final String ACTIVE_ATTR = "active";
     private static final String LAST_EVENT_ATTR = "lastEvent";
     private static final String TYPE_ATTR = "type";
+    private static final String SHORTCUT_ID_ATTR = "shortcutId";
 
     // Time attributes stored as an offset of the beginTime.
     private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
@@ -106,9 +107,15 @@
         event.mTimeStamp = statsOut.beginTime + XmlUtils.readLongAttribute(parser, TIME_ATTR);
 
         event.mEventType = XmlUtils.readIntAttribute(parser, TYPE_ATTR);
-        if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE) {
-            event.mConfiguration = new Configuration();
-            Configuration.readXmlAttrs(parser, event.mConfiguration);
+        switch (event.mEventType) {
+            case UsageEvents.Event.CONFIGURATION_CHANGE:
+                event.mConfiguration = new Configuration();
+                Configuration.readXmlAttrs(parser, event.mConfiguration);
+                break;
+            case UsageEvents.Event.SHORTCUT_INVOCATION:
+                final String id = XmlUtils.readStringAttribute(parser, SHORTCUT_ID_ATTR);
+                event.mShortcutId = (id != null) ? id.intern() : null;
+                break;
         }
 
         if (statsOut.events == null) {
@@ -165,9 +172,17 @@
         }
         XmlUtils.writeIntAttribute(xml, TYPE_ATTR, event.mEventType);
 
-        if (event.mEventType == UsageEvents.Event.CONFIGURATION_CHANGE
-                && event.mConfiguration != null) {
-            Configuration.writeXmlAttrs(xml, event.mConfiguration);
+        switch (event.mEventType) {
+            case UsageEvents.Event.CONFIGURATION_CHANGE:
+                if (event.mConfiguration != null) {
+                    Configuration.writeXmlAttrs(xml, event.mConfiguration);
+                }
+                break;
+            case UsageEvents.Event.SHORTCUT_INVOCATION:
+                if (event.mShortcutId != null) {
+                    XmlUtils.writeStringAttribute(xml, SHORTCUT_ID_ATTR, event.mShortcutId);
+                }
+                break;
         }
 
         xml.endTag(null, EVENT_TAG);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 7d003f3..59e4c80 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -549,6 +549,9 @@
             if (event.mConfiguration != null) {
                 pw.printPair("config", Configuration.resourceQualifierString(event.mConfiguration));
             }
+            if (event.mShortcutId != null) {
+                pw.printPair("shortcutId", event.mShortcutId);
+            }
             pw.println();
         }
         pw.decreaseIndent();
@@ -588,6 +591,8 @@
                 return "SYSTEM_INTERACTION";
             case UsageEvents.Event.USER_INTERACTION:
                 return "USER_INTERACTION";
+            case UsageEvents.Event.SHORTCUT_INVOCATION:
+                return "SHORTCUT_INVOCATION";
             default:
                 return "UNKNOWN";
         }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 7d7e1eb..3a6d1fd 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -23,6 +23,7 @@
 
 import java.lang.String;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -104,7 +105,6 @@
      * An {@link InCallService} will only see this state if it has the
      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
      * manifest.
-     * @hide
      */
     public static final int STATE_PULLING_CALL = 11;
 
@@ -252,7 +252,6 @@
          * <p>
          * See {@link Connection#CAPABILITY_CAN_PULL_CALL} and
          * {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
-         * @hide
          */
         public static final int CAPABILITY_CAN_PULL_CALL = 0x00800000;
 
@@ -305,10 +304,14 @@
          * in its manifest.
          * <p>
          * See {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
-         * @hide
          */
         public static final int PROPERTY_IS_EXTERNAL_CALL = 0x00000040;
 
+        /**
+         * Indicates that the call has CDMA Enhanced Voice Privacy enabled.
+         */
+        public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 0x00000080;
+
         //******************************************************************************************
         // Next PROPERTY value: 0x00000100
         //******************************************************************************************
@@ -465,6 +468,9 @@
             if (hasProperty(properties, PROPERTY_IS_EXTERNAL_CALL)) {
                 builder.append(" PROPERTY_IS_EXTERNAL_CALL");
             }
+            if(hasProperty(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
+                builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
+            }
             builder.append("]");
             return builder.toString();
         }
@@ -786,7 +792,6 @@
          * @param call The {@code Call} receiving the event.
          * @param event The event.
          * @param extras Extras associated with the connection event.
-         * @hide
          */
         public void onConnectionEvent(Call call, String event, Bundle extras) {}
     }
@@ -965,7 +970,6 @@
      * An {@link InCallService} will only see calls which support this method if it has the
      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true}
      * in its manifest.
-     * @hide
      */
     public void pullExternalCall() {
         // If this isn't an external call, ignore the request.
@@ -988,7 +992,6 @@
      *
      * @param event The connection event.
      * @param extras Bundle containing extra information associated with the event.
-     * @hide
      */
     public void sendCallEvent(String event, Bundle extras) {
         mInCallAdapter.sendCallEvent(mTelecomCallId, event, extras);
@@ -1002,7 +1005,6 @@
      * extras.  Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras to add.
-     * @hide
      */
     public final void putExtras(Bundle extras) {
         if (extras == null) {
@@ -1032,7 +1034,7 @@
     }
 
     /**
-     * Adds an integer extra to this {@code Connection}.
+     * Adds an integer extra to this {@link Call}.
      *
      * @param key The extra key.
      * @param value The value.
@@ -1047,7 +1049,7 @@
     }
 
     /**
-     * Adds a string extra to this {@code Connection}.
+     * Adds a string extra to this {@link Call}.
      *
      * @param key The extra key.
      * @param value The value.
@@ -1062,10 +1064,9 @@
     }
 
     /**
-     * Removes extras from this {@code Connection}.
+     * Removes extras from this {@link Call}.
      *
      * @param keys The keys of the extras to remove.
-     * @hide
      */
     public final void removeExtras(List<String> keys) {
         if (mExtras != null) {
@@ -1080,6 +1081,15 @@
     }
 
     /**
+     * Removes extras from this {@link Call}.
+     *
+     * @param keys The keys of the extras to remove.
+     */
+    public final void removeExtras(String ... keys) {
+        removeExtras(Arrays.asList(keys));
+    }
+
+    /**
      * Obtains the parent of this {@code Call} in a conference, if any.
      *
      * @return The parent {@code Call}, or {@code null} if this {@code Call} is not a
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 9fcbfe3..be04c90 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -24,6 +24,7 @@
 import android.util.ArraySet;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
@@ -163,7 +164,6 @@
      * {@link Connection} for valid values.
      *
      * @return A bitmask of the properties of the conference call.
-     * @hide
      */
     public final int getConnectionProperties() {
         return mConnectionProperties;
@@ -395,7 +395,6 @@
      * {@link Connection} for valid values.
      *
      * @param connectionProperties A bitmask of the {@code Properties} of the conference call.
-     * @hide
      */
     public final void setConnectionProperties(int connectionProperties) {
         if (connectionProperties != mConnectionProperties) {
@@ -684,6 +683,8 @@
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras associated with this {@code Conference}.
+     * @deprecated Use {@link #putExtras(Bundle)} to add extras.  Use {@link #removeExtras(List)}
+     * to remove extras.
      */
     public final void setExtras(@Nullable Bundle extras) {
         // Add/replace any new or changed extras values.
@@ -723,7 +724,6 @@
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras to add.
-     * @hide
      */
     public final void putExtras(@NonNull Bundle extras) {
         if (extras == null) {
@@ -780,10 +780,9 @@
     }
 
     /**
-     * Removes an extra from this {@link Conference}.
+     * Removes extras from this {@link Conference}.
      *
-     * @param keys The key of the extra key to remove.
-     * @hide
+     * @param keys The keys of the extras to remove.
      */
     public final void removeExtras(List<String> keys) {
         if (keys == null || keys.isEmpty()) {
@@ -805,7 +804,25 @@
     }
 
     /**
+     * Removes extras from this {@link Conference}.
+     *
+     * @param keys The keys of the extras to remove.
+     */
+    public final void removeExtras(String ... keys) {
+        removeExtras(Arrays.asList(keys));
+    }
+
+    /**
      * Returns the extras associated with this conference.
+     * <p>
+     * Extras should be updated using {@link #putExtras(Bundle)} and {@link #removeExtras(List)}.
+     * <p>
+     * Telecom or an {@link InCallService} can also update the extras via
+     * {@link android.telecom.Call#putExtras(Bundle)}, and
+     * {@link Call#removeExtras(List)}.
+     * <p>
+     * The conference is notified of changes to the extras made by Telecom or an
+     * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
      *
      * @return The extras associated with this connection.
      */
@@ -822,7 +839,6 @@
      * {@link Call#removeExtras(List)}.
      *
      * @param extras The new extras bundle.
-     * @hide
      */
     public void onExtrasChanged(Bundle extras) {}
 
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index ef314f3..3316bc8 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -35,6 +35,7 @@
 import android.view.Surface;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
@@ -100,7 +101,6 @@
      * <p>
      * A connection can only be in this state if the {@link #PROPERTY_IS_EXTERNAL_CALL} property and
      * {@link #CAPABILITY_CAN_PULL_CALL} capability bits are set on the connection.
-     * @hide
      */
     public static final int STATE_PULLING_CALL = 7;
 
@@ -284,7 +284,6 @@
      * <p>
      * Should only be set on a {@code Connection} where {@link #PROPERTY_IS_EXTERNAL_CALL}
      * is set.
-     * @hide
      */
     public static final int CAPABILITY_CAN_PULL_CALL = 0x01000000;
 
@@ -332,13 +331,16 @@
      * external connections.  Only those {@link InCallService}s which have the
      * {@link TelecomManager#METADATA_INCLUDE_EXTERNAL_CALLS} metadata set to {@code true} in its
      * manifest will see external connections.
-     * @hide
      */
     public static final int PROPERTY_IS_EXTERNAL_CALL = 1<<4;
 
+    /**
+     * Indicates that the connection has CDMA Enhanced Voice Privacy enabled.
+     */
+    public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 1<<5;
 
     //**********************************************************************************************
-    // Next PROPERTY value: 1<<5
+    // Next PROPERTY value: 1<<6
     //**********************************************************************************************
 
     /**
@@ -391,7 +393,6 @@
      * {@link Call.Details#PROPERTY_IS_EXTERNAL_CALL} and
      * {@link Call.Details#CAPABILITY_CAN_PULL_CALL}, but the {@link ConnectionService} could not
      * pull the external call due to an error condition.
-     * @hide
      */
     public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
 
@@ -510,13 +511,6 @@
         return builder.toString();
     }
 
-    /**
-     * Builds a string representation of a properties bit-mask.
-     *
-     * @param properties The properties bit-mask.
-     * @return String representation.
-     * @hide
-     */
     public static String propertiesToString(int properties) {
         StringBuilder builder = new StringBuilder();
         builder.append("[Properties:");
@@ -541,6 +535,10 @@
             builder.append(" PROPERTY_IS_EXTERNAL_CALL");
         }
 
+        if (can(properties, PROPERTY_HAS_CDMA_VOICE_PRIVACY)) {
+            builder.append(" PROPERTY_HAS_CDMA_VOICE_PRIVACY");
+        }
+
         builder.append("]");
         return builder.toString();
     }
@@ -1384,6 +1382,15 @@
 
     /**
      * Returns the extras associated with this connection.
+     * <p>
+     * Extras should be updated using {@link #putExtras(Bundle)}.
+     * <p>
+     * Telecom or an {@link InCallService} can also update the extras via
+     * {@link android.telecom.Call#putExtras(Bundle)}, and
+     * {@link Call#removeExtras(List)}.
+     * <p>
+     * The connection is notified of changes to the extras made by Telecom or an
+     * {@link InCallService} by {@link #onExtrasChanged(Bundle)}.
      *
      * @return The extras associated with this connection.
      */
@@ -1486,7 +1493,6 @@
 
     /**
      * Returns the connection's properties, as a bit mask of the {@code PROPERTY_*} constants.
-     * @hide
      */
     public final int getConnectionProperties() {
         return mConnectionProperties;
@@ -1692,7 +1698,6 @@
      * Sets the connection's properties as a bit mask of the {@code PROPERTY_*} constants.
      *
      * @param connectionProperties The new connection properties.
-     * @hide
      */
     public final void setConnectionProperties(int connectionProperties) {
         checkImmutable();
@@ -1877,6 +1882,8 @@
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras associated with this {@code Connection}.
+     * @deprecated Use {@link #putExtras(Bundle)} to add extras.  Use {@link #removeExtras(List)}
+     * to remove extras.
      */
     public final void setExtras(@Nullable Bundle extras) {
         checkImmutable();
@@ -1917,7 +1924,6 @@
      * Keys should be fully qualified (e.g., com.example.MY_EXTRA) to avoid conflicts.
      *
      * @param extras The extras to add.
-     * @hide
      */
     public final void putExtras(@NonNull Bundle extras) {
         checkImmutable();
@@ -1975,10 +1981,9 @@
     }
 
     /**
-     * Removes an extra from this {@code Connection}.
+     * Removes extras from this {@code Connection}.
      *
-     * @param keys The key of the extra key to remove.
-     * @hide
+     * @param keys The keys of the extras to remove.
      */
     public final void removeExtras(List<String> keys) {
         if (mExtras != null) {
@@ -1997,6 +2002,15 @@
     }
 
     /**
+     * Removes extras from this {@code Connection}.
+     *
+     * @param keys The keys of the extras to remove.
+     */
+    public final void removeExtras(String ... keys) {
+        removeExtras(Arrays.asList(keys));
+    }
+
+    /**
      * Notifies this Connection that the {@link #getAudioState()} property has a new value.
      *
      * @param state The new connection audio state.
@@ -2118,7 +2132,6 @@
      * capability and {@link Connection#PROPERTY_IS_EXTERNAL_CALL} property bits must be set.
      * <p>
      * For more information on external calls, see {@link Connection#PROPERTY_IS_EXTERNAL_CALL}.
-     * @hide
      */
     public void onPullExternalCall() {}
 
@@ -2131,7 +2144,6 @@
      *
      * @param event The call event.
      * @param extras Extras associated with the call event.
-     * @hide
      */
     public void onCallEvent(String event, Bundle extras) {}
 
@@ -2144,7 +2156,6 @@
      * {@link Call#removeExtras(List)}.
      *
      * @param extras The new extras bundle.
-     * @hide
      */
     public void onExtrasChanged(Bundle extras) {}
 
@@ -2323,7 +2334,6 @@
      *
      * @param event The connection event.
      * @param extras Bundle containing extra information associated with the event.
-     * @hide
      */
     public void sendConnectionEvent(String event, Bundle extras) {
         for (Listener l : mListeners) {
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 65437d9..cf73d4f 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -67,13 +67,11 @@
     /**
      * Disconnected because the user did not locally answer the incoming call, but it was answered
      * on another device where the call was ringing.
-     * @hide
      */
     public static final int ANSWERED_ELSEWHERE = 11;
 
     /**
      * Disconnected because the call was pulled from the current device to another device.
-     * @hide
      */
     public static final int CALL_PULLED = 12;
 
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index e2399ff..df6715d 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -457,7 +457,6 @@
      * @param call The call the event is associated with.
      * @param event The event.
      * @param extras Any associated extras.
-     * @hide
      */
     public void onConnectionEvent(Call call, String event, Bundle extras) {
     }
diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java
index bf6038a..943da6d 100644
--- a/telecomm/java/android/telecom/RemoteConference.java
+++ b/telecomm/java/android/telecom/RemoteConference.java
@@ -97,7 +97,6 @@
          *
          * @param conference The {@code RemoteConference} invoking this method.
          * @param connectionProperties The new properties of the {@code RemoteConference}.
-         * @hide
          */
         public void onConnectionPropertiesChanged(
                 RemoteConference conference,
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 8e06659db..dc8eaf6 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -95,7 +95,6 @@
          *
          * @param connection The {@code RemoteConnection} invoking this method.
          * @param connectionProperties The new properties of the {@code RemoteConnection}.
-         * @hide
          */
         public void onConnectionPropertiesChanged(
                 RemoteConnection connection,
@@ -230,7 +229,6 @@
          * @param connection The {@code RemoteConnection} invoking this method.
          * @param event The connection event.
          * @param extras Extras associated with the event.
-         * @hide
          */
         public void onConnectionEvent(RemoteConnection connection, String event, Bundle extras) {}
     }
@@ -738,7 +736,6 @@
      *
      * @return A bitmask of the properties of the {@code RemoteConnection}, as defined in the
      *         {@code PROPERTY_*} constants in class {@link Connection}.
-     * @hide
      */
     public int getConnectionProperties() {
         return mConnectionProperties;
@@ -993,7 +990,6 @@
      * Instructs this {@link RemoteConnection} to pull itself to the local device.
      * <p>
      * See {@link Call#pullExternalCall()} for more information.
-     * @hide
      */
     public void pullExternalCall() {
         try {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index da0d048..ff5daaf 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -348,7 +348,6 @@
      * informed of external calls should set this meta-data to {@code true} in the manifest
      * registration of their {@link InCallService}.  By default, the {@link InCallService} will NOT
      * be informed of external calls.
-     * @hide
      */
     public static final String METADATA_INCLUDE_EXTERNAL_CALLS =
             "android.telecom.INCLUDE_EXTERNAL_CALLS";
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 5c2e0ba..af15c0a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -530,6 +530,17 @@
     public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
 
     /**
+     * Determines whether video conference calls are supported by a carrier.  When {@code true},
+     * video calls can be merged into conference calls, {@code false} otherwiwse.
+     * <p>
+     * Note: even if video conference calls are not supported, audio calls may be merged into a
+     * conference if {@link #KEY_SUPPORT_CONFERENCE_CALL_BOOL} is {@code true}.
+     * @hide
+     */
+    public static final String KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL =
+            "support_video_conference_call_bool";
+
+    /**
      * Determine whether user can toggle Enhanced 4G LTE Mode in Settings.
      */
     public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
@@ -582,6 +593,14 @@
     public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
 
     /**
+     * The Component Name of the activity that can setup the emergency addrees for WiFi Calling
+     * as per carrier requirement.
+     * @hide
+     */
+     public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING =
+            "wfc_emergency_address_carrier_app_string";
+
+    /**
      * Boolean to decide whether to use #KEY_CARRIER_NAME_STRING from CarrierConfig app.
      * @hide
      */
@@ -594,7 +613,6 @@
      */
     public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string";
 
-
     /**
      * If this is true, the SIM card (through Customer Service Profile EF file) will be able to
      * prevent manual operator selection. If false, this SIM setting will be ignored and manual
@@ -615,6 +633,13 @@
     public static final String KEY_BROADCAST_EMERGENCY_CALL_STATE_CHANGES_BOOL =
             "broadcast_emergency_call_state_changes_bool";
 
+    /**
+     * Cell broadcast additional channels enbled by the carrier
+     * @hide
+     */
+    public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
+            "carrier_additional_cbs_channels_strings";
+
     // These variables are used by the MMS service and exposed through another API, {@link
     // SmsManager}. The variable names and string values are copied from there.
     public static final String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled";
@@ -658,10 +683,44 @@
      * example:
      * <item>com.google.android.carrierPackageName</item>
      * <item>com.google.android.carrierPackageName.CarrierActivityName</item>
+     * The ComponentName of the carrier activity that can setup the device and activate with the
+     * network as part of the Setup Wizard flow.
      * @hide
      */
-     public static final String KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY =
-            "sim_state_detection_carrier_app_string_array";
+     public static final String KEY_CARRIER_SETUP_APP_STRING = "carrier_setup_app_string";
+
+    /**
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_REDIRECTED.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
+     * @hide
+     */
+    public static final String KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY =
+            "signal_redirection_receiver_string_array";
+
+    /**
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
+     * @hide
+     */
+    public static final String KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY =
+            "signal_dcfailure_receiver_string_array";
+
+    /**
+     * A list of component name of carrier signalling receivers which are interested in intent
+     * android.intent.action.CARRIER_SIGNAL_PCO_VALUE.
+     * Example:
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameA</item>
+     * <item>com.google.android.carrierPackageName/.CarrierSignalReceiverNameB</item>
+     * @hide
+     */
+    public static final String KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY =
+            "signal_pco_receiver_string_array";
 
     /**
      * Determines whether the carrier supports making non-emergency phone calls while the phone is
@@ -790,6 +849,7 @@
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_VIDEO_CONFERENCE_CALL_BOOL, false);
         sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
         sDefaults.putBoolean(KEY_HIDE_IMS_APN_BOOL, false);
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
@@ -798,6 +858,7 @@
         sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
         sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
         sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
+        sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, "");
         sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false);
         sDefaults.putBoolean(KEY_CARRIER_NAME_OVERRIDE_BOOL, false);
         sDefaults.putString(KEY_CARRIER_NAME_STRING, "");
@@ -837,9 +898,11 @@
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
 
-        // Used for Sim card State detection app
-        sDefaults.putStringArray(KEY_SIM_PROVISIONING_STATUS_DETECTION_CARRIER_APP_STRING_ARRAY,
-                null);
+        // Carrier Signalling Receivers
+        sDefaults.putStringArray(KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_SIGNAL_DCFAILURE_RECEIVER_STRING_ARRAY, null);
+        sDefaults.putStringArray(KEY_SIGNAL_PCO_RECEIVER_STRING_ARRAY, null);
+        sDefaults.putString(KEY_CARRIER_SETUP_APP_STRING, "");
     }
 
     /**
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 9eb1304..7a9170f 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -194,6 +194,12 @@
      */
     public static final int VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED = 50;
 
+    /**
+     * The call was terminated because it was pulled to another device.
+     * {@hide}
+     */
+    public static final int CALL_PULLED = 51;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Please assign the new type the next id value below.
@@ -318,7 +324,9 @@
         case CDMA_ALREADY_ACTIVATED:
             return "CDMA_ALREADY_ACTIVATED";
         case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
-                return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED";
+            return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED";
+        case CALL_PULLED:
+            return "CALL_PULLED";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/PcoData.aidl b/telephony/java/android/telephony/PcoData.aidl
new file mode 100644
index 0000000..a93b8d3
--- /dev/null
+++ b/telephony/java/android/telephony/PcoData.aidl
@@ -0,0 +1,21 @@
+/*
+**
+** Copyright (C) 2016 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.telephony;
+
+parcelable PcoData;
+
diff --git a/telephony/java/android/telephony/PcoData.java b/telephony/java/android/telephony/PcoData.java
new file mode 100644
index 0000000..3e735e7
--- /dev/null
+++ b/telephony/java/android/telephony/PcoData.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Contains Carrier-specific (and opaque) Protocol configuration Option
+ * Data.  In general this is only passed on to carrier-specific applications
+ * for interpretation.
+ *
+ * @hide
+ */
+public class PcoData implements Parcelable {
+
+    public final int cid;
+    public final String bearerProto;
+    public final int pcoId;
+    public final byte[] contents;
+
+    public PcoData(int cid, String bearerProto, int pcoId, byte[]contents) {
+        this.cid = cid;
+        this.bearerProto = bearerProto;
+        this.pcoId = pcoId;
+        this.contents = contents;
+    }
+
+    public PcoData(Parcel in) {
+        cid = in.readInt();
+        bearerProto = in.readString();
+        pcoId = in.readInt();
+        contents = in.createByteArray();
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(cid);
+        out.writeString(bearerProto);
+        out.writeInt(pcoId);
+        out.writeByteArray(contents);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable.Creator}
+     *
+     * @hide
+     */
+    public static final Parcelable.Creator<PcoData> CREATOR = new Parcelable.Creator() {
+        public PcoData createFromParcel(Parcel in) {
+            return new PcoData(in);
+        }
+
+        public PcoData[] newArray(int size) {
+            return new PcoData[size];
+        }
+    };
+
+    @Override
+    public String toString() {
+        return "PcoData(" + cid + ", " + bearerProto + ", " + pcoId + ", contents[" +
+                contents.length + "])";
+    }
+}
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 962a600..03d6d21 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -30,6 +30,7 @@
 import android.os.SystemProperties;
 import android.provider.Contacts;
 import android.provider.ContactsContract;
+import android.telecom.PhoneAccount;
 import android.text.Editable;
 import android.text.Spannable;
 import android.text.SpannableStringBuilder;
@@ -2599,6 +2600,48 @@
     }
 
     /**
+     * Given a {@link Uri} with a {@code sip} scheme, attempts to build an equivalent {@code tel}
+     * scheme {@link Uri}.  If the source {@link Uri} does not contain a valid number, or is not
+     * using the {@code sip} scheme, the original {@link Uri} is returned.
+     *
+     * @param source The {@link Uri} to convert.
+     * @return The equivalent {@code tel} scheme {@link Uri}.
+     *
+     * @hide
+     */
+    public static Uri convertSipUriToTelUri(Uri source) {
+        // A valid SIP uri has the format: sip:user:password@host:port;uri-parameters?headers
+        // Per RFC3261, the "user" can be a telephone number.
+        // For example: sip:1650555121;phone-context=blah.com@host.com
+        // In this case, the phone number is in the user field of the URI, and the parameters can be
+        // ignored.
+        //
+        // A SIP URI can also specify a phone number in a format similar to:
+        // sip:+1-212-555-1212@something.com;user=phone
+        // In this case, the phone number is again in user field and the parameters can be ignored.
+        // We can get the user field in these instances by splitting the string on the @, ;, or :
+        // and looking at the first found item.
+
+        String scheme = source.getScheme();
+
+        if (!PhoneAccount.SCHEME_SIP.equals(scheme)) {
+            // Not a sip URI, bail.
+            return source;
+        }
+
+        String number = source.getSchemeSpecificPart();
+        String numberParts[] = number.split("[@;:]");
+
+        if (numberParts.length == 0) {
+            // Number not found, bail.
+            return source;
+        }
+        number = numberParts[0];
+
+        return Uri.fromParts(PhoneAccount.SCHEME_TEL, number, null);
+    }
+
+    /**
      * This function handles the plus code conversion
      * If the number format is
      * 1)+1NANP,remove +,
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b5cf212e..6229ed9 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -90,14 +90,6 @@
     private int mDataRoaming;
 
     /**
-     * Sim Provisioning Status:
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     */
-    private int mSimProvisioningStatus;
-
-    /**
      * SIM Icon bitmap
      */
     private Bitmap mIconBitmap;
@@ -122,7 +114,7 @@
      */
     public SubscriptionInfo(int id, String iccId, int simSlotIndex, CharSequence displayName,
             CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
-            Bitmap icon, int mcc, int mnc, String countryIso, int simProvisioningStatus) {
+            Bitmap icon, int mcc, int mnc, String countryIso) {
         this.mId = id;
         this.mIccId = iccId;
         this.mSimSlotIndex = simSlotIndex;
@@ -136,7 +128,6 @@
         this.mMcc = mcc;
         this.mMnc = mnc;
         this.mCountryIso = countryIso;
-        this.mSimProvisioningStatus = simProvisioningStatus;
     }
 
     /**
@@ -273,17 +264,6 @@
     }
 
     /**
-     * @return Sim Provisioning Status
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @hide
-     */
-    public int getSimProvisioningStatus() {
-        return this.mSimProvisioningStatus;
-    }
-
-    /**
      * @return the MCC.
      */
     public int getMcc() {
@@ -319,12 +299,10 @@
             int mcc = source.readInt();
             int mnc = source.readInt();
             String countryIso = source.readString();
-            int simProvisioningStatus = source.readInt();
             Bitmap iconBitmap = Bitmap.CREATOR.createFromParcel(source);
 
             return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
-                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
-                    simProvisioningStatus);
+                    nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso);
         }
 
         @Override
@@ -347,7 +325,6 @@
         dest.writeInt(mMcc);
         dest.writeInt(mMnc);
         dest.writeString(mCountryIso);
-        dest.writeInt(mSimProvisioningStatus);
         mIconBitmap.writeToParcel(dest, flags);
     }
 
@@ -378,6 +355,6 @@
                 + " displayName=" + mDisplayName + " carrierName=" + mCarrierName
                 + " nameSource=" + mNameSource + " iconTint=" + mIconTint
                 + " dataRoaming=" + mDataRoaming + " iconBitmap=" + mIconBitmap + " mcc " + mMcc
-                + " mnc " + mMnc + " SimProvisioningStatus " + mSimProvisioningStatus +"}";
+                + " mnc " + mMnc + "}";
     }
 }
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index c49966a..dd6f9cb 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -232,25 +232,12 @@
     /** Indicates that data roaming is disabled for a subscription */
     public static final int DATA_ROAMING_DISABLE = 0;
 
-    /** Sim provisioning status: provisioned */
-    /** @hide */
-    public static final int SIM_PROVISIONED = 0;
-
-    /** Sim provisioning status: un-provisioned due to cold sim */
-    /** @hide */
-    public static final int SIM_UNPROVISIONED_COLD = 1;
-
-    /** Sim provisioning status: un-provisioned due to out of credit */
-    /** @hide */
-    public static final int SIM_UNPROVISIONED_OUT_OF_CREDIT = 2;
-
-    /** Maximum possible sim provisioning status */
-    /** @hide */
-    public static final int MAX_SIM_PROVISIONING_STATUS = SIM_UNPROVISIONED_OUT_OF_CREDIT;
-
     /** @hide */
     public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
 
+    /** @hide */
+    public static final int SIM_PROVISIONED = 0;
+
     /**
      * TelephonyProvider column name for the MCC associated with a SIM.
      * <P>Type: INTEGER (int)</P>
@@ -843,40 +830,6 @@
     }
 
     /**
-     * Set Sim Provisioning Status by subscription ID
-     * @param simProvisioningStatus with the subscription
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @param subId the unique SubInfoRecord index in database
-     * @return the number of records updated
-     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
-     * @hide
-     */
-    public int setSimProvisioningStatus(int simProvisioningStatus, int subId) {
-        if (VDBG) {
-            logd("[setSimProvisioningStatus]+ status:" + simProvisioningStatus + " subId:" + subId);
-        }
-        if (simProvisioningStatus < 0 || simProvisioningStatus > MAX_SIM_PROVISIONING_STATUS ||
-                !isValidSubscriptionId(subId)) {
-            logd("[setSimProvisioningStatus]- fail");
-            return -1;
-        }
-
-        int result = 0;
-
-        try {
-            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
-            if (iSub != null) {
-                result = iSub.setSimProvisioningStatus(simProvisioningStatus, subId);
-            }
-        } catch (RemoteException ex) {
-            // ignore it
-        }
-        return result;
-    }
-
-    /**
      * Get slotId associated with the subscription.
      * @return slotId as a positive integer or a negative value if an error either
      * SIM_NOT_INSERTED or < 0 if an invalid slot index
diff --git a/telephony/java/android/telephony/TelephonyHistogram.aidl b/telephony/java/android/telephony/TelephonyHistogram.aidl
new file mode 100644
index 0000000..8de81cf
--- /dev/null
+++ b/telephony/java/android/telephony/TelephonyHistogram.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+/**
+ * @hide
+ */
+parcelable TelephonyHistogram;
diff --git a/telephony/java/android/telephony/TelephonyHistogram.java b/telephony/java/android/telephony/TelephonyHistogram.java
new file mode 100644
index 0000000..9d9ce72
--- /dev/null
+++ b/telephony/java/android/telephony/TelephonyHistogram.java
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Parcelable class to store Telephony histogram.
+ * @hide
+ */
+@SystemApi
+public final class TelephonyHistogram implements Parcelable {
+    // Type of Telephony histogram Eg: RIL histogram will have all timing data associated with
+    // RIL calls. Similarly we can have any other Telephony histogram.
+    private final int category;
+
+    // Unique Id identifying a sample within particular category of histogram
+    private final int id;
+
+    // Min time taken in ms
+    private int minTimeMs;
+
+    // Max time taken in ms
+    private int maxTimeMs;
+
+    // Average time taken in ms
+    private int averageTimeMs;
+
+    // Total count of samples
+    private int sampleCount;
+
+    // Array storing time taken for first #RANGE_CALCULATION_COUNT samples of histogram.
+    private int[] initialTimings;
+
+    // Total number of time ranges expected (must be greater than 1)
+    private final int bucketCount;
+
+    // Array storing endpoints of range buckets. Calculated based on values of minTime & maxTime
+    // after totalTimeCount is #RANGE_CALCULATION_COUNT.
+    private final int[] bucketEndPoints;
+
+    // Array storing counts for each time range starting from smallest value range
+    private final int[] bucketCounters;
+
+    /**
+     * Constant for Telephony category
+     */
+    public static final int TELEPHONY_CATEGORY_RIL = 1;
+
+    // Count of Histogram samples after which time buckets are created.
+    private static final int RANGE_CALCULATION_COUNT = 10;
+
+
+    // Constant used to indicate #initialTimings is null while parceling
+    private static final int ABSENT = 0;
+
+    // Constant used to indicate #initialTimings is not null while parceling
+    private static final int PRESENT = 1;
+
+    // Throws exception if #totalBuckets is not greater than one.
+    public TelephonyHistogram (int category, int id, int bucketCount) {
+        if (bucketCount <= 1) {
+            throw new IllegalArgumentException("Invalid number of buckets");
+        }
+        this.category = category;
+        this.id = id;
+        this.minTimeMs = Integer.MAX_VALUE;
+        this.maxTimeMs = 0;
+        this.averageTimeMs = 0;
+        this.sampleCount = 0;
+        initialTimings = new int[RANGE_CALCULATION_COUNT];
+        this.bucketCount = bucketCount;
+        bucketEndPoints = new int[bucketCount - 1];
+        bucketCounters = new int[bucketCount];
+    }
+
+    public TelephonyHistogram(TelephonyHistogram th) {
+        category = th.getCategory();
+        id = th.getId();
+        minTimeMs = th.getMinTime();
+        maxTimeMs = th.getMaxTime();
+        averageTimeMs = th.getAverageTime();
+        sampleCount = th.getSampleCount();
+        initialTimings = th.getInitialTimings();
+        bucketCount = th.getBucketCount();
+        bucketEndPoints = th.getBucketEndPoints();
+        bucketCounters = th.getBucketCounters();
+    }
+
+    public int getCategory() {
+        return category;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public int getMinTime() {
+        return minTimeMs;
+    }
+
+    public int getMaxTime() {
+        return maxTimeMs;
+    }
+
+    public int getAverageTime() {
+        return averageTimeMs;
+    }
+
+    public int getSampleCount () {
+        return sampleCount;
+    }
+
+    private int[] getInitialTimings() {
+        return initialTimings;
+    }
+
+    public int getBucketCount() {
+        return bucketCount;
+    }
+
+    public int[] getBucketEndPoints() {
+        return getDeepCopyOfArray(bucketEndPoints);
+    }
+
+    public int[] getBucketCounters() {
+        return getDeepCopyOfArray(bucketCounters);
+    }
+
+    private int[] getDeepCopyOfArray(int[] array) {
+        int[] clone = new int[array.length];
+        System.arraycopy(array, 0, clone, 0, array.length);
+        return clone;
+    }
+
+    private void addToBucketCounter(int time) {
+        int i;
+        for (i = 0; i < bucketEndPoints.length; i++) {
+            if (time <= bucketEndPoints[i]) {
+                bucketCounters[i]++;
+                return;
+            }
+        }
+        bucketCounters[i]++;
+    }
+
+    // Add new value of time taken
+    // This function updates minTime, maxTime, averageTime & totalTimeCount every time it is
+    // called. initialTimings[] is updated if totalTimeCount <= #RANGE_CALCULATION_COUNT. When
+    // totalTimeCount = RANGE_CALCULATION_COUNT, based on the min, max time & the number of buckets
+    // expected, bucketEndPoints[] would be calculated. Then bucketCounters[] would be filled up
+    // using values stored in initialTimings[]. Thereafter bucketCounters[] will always be updated.
+    public void addTimeTaken(int time) {
+        // Initialize all fields if its first entry or if integer overflow is going to occur while
+        // trying to calculate averageTime
+        if (sampleCount == 0 || (sampleCount == Integer.MAX_VALUE)) {
+            if (sampleCount == 0) {
+                minTimeMs = time;
+                maxTimeMs = time;
+                averageTimeMs = time;
+            } else {
+                initialTimings = new int[RANGE_CALCULATION_COUNT];
+            }
+            sampleCount = 1;
+            Arrays.fill(initialTimings, 0);
+            initialTimings[0] = time;
+            Arrays.fill(bucketEndPoints, 0);
+            Arrays.fill(bucketCounters, 0);
+        } else {
+            if (time < minTimeMs) {
+                minTimeMs = time;
+            }
+            if (time > maxTimeMs) {
+                maxTimeMs = time;
+            }
+            long totalTime = ((long)averageTimeMs) * sampleCount + time;
+            averageTimeMs = (int)(totalTime/++sampleCount);
+
+            if (sampleCount < RANGE_CALCULATION_COUNT) {
+                initialTimings[sampleCount - 1] = time;
+            } else if (sampleCount == RANGE_CALCULATION_COUNT) {
+                initialTimings[sampleCount - 1] = time;
+
+                // Calculate bucket endpoints based on bucketCount expected
+                for (int i = 1; i < bucketCount; i++) {
+                    int endPt = minTimeMs + (i * (maxTimeMs - minTimeMs)) / bucketCount;
+                    bucketEndPoints[i - 1] = endPt;
+                }
+
+                // Use values stored in initialTimings[] to update bucketCounters
+                for (int j = 0; j < RANGE_CALCULATION_COUNT; j++) {
+                    addToBucketCounter(initialTimings[j]);
+                }
+                initialTimings = null;
+            } else {
+                addToBucketCounter(time);
+            }
+
+        }
+    }
+
+    public String toString() {
+        String basic = " Histogram id = " + id + " Time(ms): min = " + minTimeMs + " max = "
+                + maxTimeMs + " avg = " + averageTimeMs + " Count = " + sampleCount;
+        if (sampleCount < RANGE_CALCULATION_COUNT) {
+            return basic;
+        } else {
+            StringBuffer intervals = new StringBuffer(" Interval Endpoints:");
+            for (int i = 0; i < bucketEndPoints.length; i++) {
+                intervals.append(" " + bucketEndPoints[i]);
+            }
+            intervals.append(" Interval counters:");
+            for (int i = 0; i < bucketCounters.length; i++) {
+                intervals.append(" " + bucketCounters[i]);
+            }
+            return basic + intervals;
+        }
+    }
+
+    public static final Parcelable.Creator<TelephonyHistogram> CREATOR =
+            new Parcelable.Creator<TelephonyHistogram> () {
+
+                @Override
+                public TelephonyHistogram createFromParcel(Parcel in) {
+                    return new TelephonyHistogram(in);
+                }
+
+                @Override
+                public TelephonyHistogram[] newArray(int size) {
+                    return new TelephonyHistogram[size];
+                }
+            };
+
+    public TelephonyHistogram(Parcel in) {
+        category = in.readInt();
+        id = in.readInt();
+        minTimeMs = in.readInt();
+        maxTimeMs = in.readInt();
+        averageTimeMs = in.readInt();
+        sampleCount = in.readInt();
+        if (in.readInt() == PRESENT) {
+            initialTimings = new int[RANGE_CALCULATION_COUNT];
+            in.readIntArray(initialTimings);
+        }
+        bucketCount = in.readInt();
+        bucketEndPoints = new int[bucketCount - 1];
+        in.readIntArray(bucketEndPoints);
+        bucketCounters = new int[bucketCount];
+        in.readIntArray(bucketCounters);
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(category);
+        out.writeInt(id);
+        out.writeInt(minTimeMs);
+        out.writeInt(maxTimeMs);
+        out.writeInt(averageTimeMs);
+        out.writeInt(sampleCount);
+        if (initialTimings == null) {
+            out.writeInt(ABSENT);
+        } else {
+            out.writeInt(PRESENT);
+            out.writeIntArray(initialTimings);
+        }
+        out.writeInt(bucketCount);
+        out.writeIntArray(bucketEndPoints);
+        out.writeIntArray(bucketCounters);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2304346..e72fe49 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -34,8 +34,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyHistogram;
 import android.util.Log;
 
 import com.android.internal.telecom.ITelecomService;
@@ -50,6 +52,7 @@
 
 import java.io.FileInputStream;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.regex.Matcher;
@@ -1756,6 +1759,11 @@
      *@hide
      */
     public static final int SIM_STATE_CARD_IO_ERROR = 8;
+    /** SIM card state: SIM Card restricted, present but not usable due to
+     * carrier restrictions.
+     *@hide
+     */
+    public static final int SIM_STATE_CARD_RESTRICTED = 9;
 
     /**
      * @return true if a ICC card is present
@@ -1909,7 +1917,7 @@
         return getSimOperatorNumericForPhone(phoneId);
     }
 
-   /**
+    /**
      * Returns the MCC+MNC (mobile country code + mobile network code) of the
      * provider of the SIM for a particular subscription. 5 or 6 decimal digits.
      * <p>
@@ -2461,6 +2469,102 @@
     }
 
     /**
+     * Enables the visual voicemail SMS filter for a phone account. When the filter is
+     * enabled, Incoming SMS messages matching the OMTP VVM SMS interface will be redirected to the
+     * visual voicemail client with
+     * {@link android.provider.VoicemailContract.ACTION_VOICEMAIL_SMS_RECEIVED}.
+     *
+     * <p>This takes effect only when the caller is the default dialer. The enabled status and
+     * settings persist through default dialer changes, but the filter will only honor the setting
+     * set by the current default dialer.
+     *
+     *
+     * @param subId The subscription id of the phone account.
+     * @param settings The settings for the filter.
+     */
+    /** @hide */
+    public void enableVisualVoicemailSmsFilter(int subId,
+            VisualVoicemailSmsFilterSettings settings) {
+        if(settings == null){
+            throw new IllegalArgumentException("Settings cannot be null");
+        }
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.enableVisualVoicemailSmsFilter(mContext.getOpPackageName(), subId,
+                        settings);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
+
+    /**
+     * Disables the visual voicemail SMS filter for a phone account.
+     *
+     * <p>This takes effect only when the caller is the default dialer. The enabled status and
+     * settings persist through default dialer changes, but the filter will only honor the setting
+     * set by the current default dialer.
+     */
+    /** @hide */
+    public void disableVisualVoicemailSmsFilter(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                telephony.disableVisualVoicemailSmsFilter(mContext.getOpPackageName(), subId);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+    }
+
+    /**
+     * @returns the settings of the visual voicemail SMS filter for a phone account, or {@code null}
+     * if the filter is disabled.
+     *
+     * <p>This takes effect only when the caller is the default dialer. The enabled status and
+     * settings persist through default dialer changes, but the filter will only honor the setting
+     * set by the current default dialer.
+     */
+    /** @hide */
+    @Nullable
+    public VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony
+                        .getVisualVoicemailSmsFilterSettings(mContext.getOpPackageName(), subId);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+
+        return null;
+    }
+
+    /**
+     * @returns the settings of the visual voicemail SMS filter for a phone account set by the
+     * package, or {@code null} if the filter is disabled.
+     *
+     * <p>Requires the calling app to have READ_PRIVILEGED_PHONE_STATE permission.
+     */
+    /** @hide */
+    @Nullable
+    public VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String packageName,
+            int subId) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getSystemVisualVoicemailSmsFilterSettings(packageName, subId);
+            }
+        } catch (RemoteException ex) {
+        } catch (NullPointerException ex) {
+        }
+
+        return null;
+    }
+
+    /**
      * Returns the voice mail count. Return 0 if unavailable, -1 if there are unread voice messages
      * but the count is unknown.
      * <p>
@@ -5246,4 +5350,170 @@
         }
         return false;
     }
+
+    /**
+     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+     *
+     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+     *
+     * @param appType the uicc app type like {@link APPTYPE_CSIM}
+     * @return Application ID for specificied app type or null if no uicc or error.
+     * @hide
+     */
+    public String getAidForAppType(int appType) {
+        return getAidForAppType(getDefaultSubscription(), appType);
+    }
+
+    /**
+     * Return the application ID for the app type like {@link APPTYPE_CSIM}.
+     *
+     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+     *
+     * @param subId the subscription ID that this request applies to.
+     * @param appType the uicc app type, like {@link APPTYPE_CSIM}
+     * @return Application ID for specificied app type or null if no uicc or error.
+     * @hide
+     */
+    public String getAidForAppType(int subId, int appType) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getAidForAppType(subId, appType);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getAidForAppType", e);
+        }
+        return null;
+    }
+
+    /**
+     * Return the Electronic Serial Number.
+     *
+     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+     *
+     * @return ESN or null if error.
+     * @hide
+     */
+    public String getEsn() {
+        return getEsn(getDefaultSubscription());
+    }
+
+    /**
+     * Return the Electronic Serial Number.
+     *
+     * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+     *
+     * @param subId the subscription ID that this request applies to.
+     * @return ESN or null if error.
+     * @hide
+     */
+    public String getEsn(int subId) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getEsn(subId);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getEsn", e);
+        }
+        return null;
+    }
+
+    /*
+     * Get snapshot of Telephony histograms
+     * @return List of Telephony histograms
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges.
+     * @hide
+     */
+    @SystemApi
+    public List<TelephonyHistogram> getTelephonyHistograms() {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getTelephonyHistograms();
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getTelephonyHistograms", e);
+        }
+        return null;
+    }
+
+    /**
+     * Set the allowed carrier list for slotId
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return The number of carriers set successfully. Should be length of
+     * carrierList on success; -1 on error.
+     * @hide
+     */
+    public int setAllowedCarriers(int slotId, List<CarrierIdentifier> carriers) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.setAllowedCarriers(slotId, carriers);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
+        }
+        return -1;
+    }
+
+    /**
+     * Get the allowed carrier list for slotId.
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return List of {@link android.telephony.CarrierIdentifier}; empty list
+     * means all carriers are allowed.
+     * @hide
+     */
+    public List<CarrierIdentifier> getAllowedCarriers(int slotId) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.getAllowedCarriers(slotId);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
+        }
+        return new ArrayList<CarrierIdentifier>(0);
+    }
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable metered apns
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable metered apns.
+     * @hide
+     */
+    public void carrierActionSetMeteredApnsEnabled(int subId, boolean enabled) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.carrierActionSetMeteredApnsEnabled(subId, enabled);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#carrierActionSetMeteredApnsEnabled", e);
+        }
+    }
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable radio
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable radio.
+     * @hide
+     */
+    public void carrierActionSetRadioEnabled(int subId, boolean enabled) {
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                service.carrierActionSetRadioEnabled(subId, enabled);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error calling ITelephony#carrierActionSetRadioEnabled", e);
+        }
+    }
 }
+
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.aidl b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.aidl
new file mode 100644
index 0000000..4b0539d
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.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 android.telephony;
+
+parcelable VisualVoicemailSmsFilterSettings;
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
new file mode 100644
index 0000000..5b81027
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Class to represent various settings for the visual voicemail SMS filter. When the filter is
+ * enabled, incoming SMS matching the generalized OMTP format:
+ *
+ * <p>[clientPrefix]:[prefix]:([key]=[value];)*
+ *
+ * <p>will be regarded as a visual voicemail SMS, and removed before reaching the SMS provider. The
+ * intent {@link android.provider.VoicemailContract#ACTION_VOICEMAIL_SMS_RECEIVED} will then be sent
+ * to the default dialer with the information extracted from the SMS.
+ *
+ * <p>Use {@link android.telephony.VisualVoicemailSmsFilterSettings.Builder} to construct this
+ * class.
+ *
+ * @see android.telephony.TelephonyManager#enableVisualVoicemailSmsFilter
+ *
+ * @hide
+ */
+public class VisualVoicemailSmsFilterSettings implements Parcelable {
+
+
+    /**
+     * The visual voicemail SMS message does not have to be a data SMS, and can be directed to any
+     * port.
+     *
+     * @hide
+     */
+    public static final int DESTINATION_PORT_ANY = -1;
+
+    /**
+     * The visual voicemail SMS message can be directed to any port, but must be a data SMS.
+     *
+     * @hide
+     */
+    public static final int DESTINATION_PORT_DATA_SMS = -2;
+
+    public static final String DEFAULT_CLIENT_PREFIX = "//VVM";
+    public static final List<String> DEFAULT_ORIGINATING_NUMBERS = Collections.emptyList();
+    public static final int DEFAULT_DESTINATION_PORT = DESTINATION_PORT_ANY;
+
+    /**
+     * Builder class for {@link VisualVoicemailSmsFilterSettings} objects.
+     *
+     * @hide
+     */
+    public static class Builder {
+
+        private String mClientPrefix = DEFAULT_CLIENT_PREFIX;
+        private List<String> mOriginatingNumbers = DEFAULT_ORIGINATING_NUMBERS;
+        private int mDestinationPort = DEFAULT_DESTINATION_PORT;
+
+        public VisualVoicemailSmsFilterSettings build() {
+            return new VisualVoicemailSmsFilterSettings(this);
+        }
+
+        /**
+         * Sets the client prefix for the visual voicemail SMS filter. The client prefix will appear
+         * at the start of a visual voicemail SMS message, followed by a colon(:).
+         */
+        public Builder setClientPrefix(String clientPrefix) {
+            if (clientPrefix == null) {
+                throw new IllegalArgumentException("Client prefix cannot be null");
+            }
+            mClientPrefix = clientPrefix;
+            return this;
+        }
+
+        /**
+         * Sets the originating number whitelist for the visual voicemail SMS filter. If the list is
+         * not null only the SMS messages from a number in the list can be considered as a visual
+         * voicemail SMS. Otherwise, messages from any address will be considered.
+         */
+        public Builder setOriginatingNumbers(List<String> originatingNumbers) {
+            if (originatingNumbers == null) {
+                throw new IllegalArgumentException("Originating numbers cannot be null");
+            }
+            mOriginatingNumbers = originatingNumbers;
+            return this;
+        }
+
+        /**
+         * Sets the destination port for the visual voicemail SMS filter.
+         *
+         * @param destinationPort The destination port, or {@link #DESTINATION_PORT_ANY}, or {@link
+         * #DESTINATION_PORT_DATA_SMS}
+         */
+        public Builder setDestinationPort(int destinationPort) {
+            mDestinationPort = destinationPort;
+            return this;
+        }
+
+    }
+
+    /**
+     * The client prefix for the visual voicemail SMS filter. The client prefix will appear at the
+     * start of a visual voicemail SMS message, followed by a colon(:).
+     */
+    public final String clientPrefix;
+
+    /**
+     * The originating number whitelist for the visual voicemail SMS filter of a phone account. If
+     * the list is not null only the SMS messages from a number in the list can be considered as a
+     * visual voicemail SMS. Otherwise, messages from any address will be considered.
+     */
+    public final List<String> originatingNumbers;
+
+    /**
+     * The destination port for the visual voicemail SMS filter, or {@link #DESTINATION_PORT_ANY},
+     * or {@link #DESTINATION_PORT_DATA_SMS}
+     */
+    public final int destinationPort;
+
+    /**
+     * Use {@link Builder} to construct
+     */
+    private VisualVoicemailSmsFilterSettings(Builder builder) {
+        clientPrefix = builder.mClientPrefix;
+        originatingNumbers = builder.mOriginatingNumbers;
+        destinationPort = builder.mDestinationPort;
+    }
+
+    public static final Creator<VisualVoicemailSmsFilterSettings> CREATOR =
+            new Creator<VisualVoicemailSmsFilterSettings>() {
+                @Override
+                public VisualVoicemailSmsFilterSettings createFromParcel(Parcel in) {
+                    Builder builder = new Builder();
+                    builder.setClientPrefix(in.readString());
+                    builder.setOriginatingNumbers(in.createStringArrayList());
+                    builder.setDestinationPort(in.readInt());
+
+                    return builder.build();
+                }
+
+                @Override
+                public VisualVoicemailSmsFilterSettings[] newArray(int size) {
+                    return new VisualVoicemailSmsFilterSettings[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(clientPrefix);
+        dest.writeStringList(originatingNumbers);
+        dest.writeInt(destinationPort);
+    }
+
+}
diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl
index a9614a6..406d22d 100644
--- a/telephony/java/com/android/ims/internal/IImsService.aidl
+++ b/telephony/java/com/android/ims/internal/IImsService.aidl
@@ -38,8 +38,19 @@
     void close(int serviceId);
     boolean isConnected(int serviceId, int serviceType, int callType);
     boolean isOpened(int serviceId);
+
+    /**
+     * Replace existing registration listener
+     *
+     */
     void setRegistrationListener(int serviceId, in IImsRegistrationListener listener);
 
+    /**
+     * Add new registration listener
+     */
+    void addRegistrationListener(int phoneId, int serviceClass,
+            in IImsRegistrationListener listener);
+
     ImsCallProfile createCallProfile(int serviceId, int serviceType, int callType);
 
     IImsCallSession createCallSession(int serviceId, in ImsCallProfile profile,
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index c61ed2a..f6aef08 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -118,17 +118,6 @@
     int setDisplayName(String displayName, int subId);
 
     /**
-     * Set Sim Provisioning Status by subscription ID
-     * @param simProvisionStatus with the subscription:
-     * {@See SubscriptionManager#SIM_PROVISIONED}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_COLD}
-     * {@See SubscriptionManager#SIM_UNPROVISIONED_OUT_OF_CREDIT}
-     * @param subId the unique SubInfoRecord index in database
-     * @return the number of records updated
-     */
-    int setSimProvisioningStatus(int simProvisioningStatus, int subId);
-
-    /**
      * Set display name by simInfo index with name source
      * @param displayName the display name of SIM card
      * @param subId the unique SubscriptionInfo index in database
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bb8aaad5..2171c9e 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -20,6 +20,7 @@
 import android.os.Bundle;
 import android.os.ResultReceiver;
 import android.net.Uri;
+import android.service.carrier.CarrierIdentifier;
 import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
 import android.telephony.CellInfo;
@@ -28,8 +29,11 @@
 import android.telephony.NeighboringCellInfo;
 import android.telephony.RadioAccessFamily;
 import android.telephony.ServiceState;
+import android.telephony.TelephonyHistogram;
+import android.telephony.VisualVoicemailSmsFilterSettings;
 import com.android.internal.telephony.CellNetworkScanResult;
 import com.android.internal.telephony.OperatorInfo;
+
 import java.util.List;
 
 
@@ -450,6 +454,20 @@
      */
     int getVoiceMessageCountForSubscriber(int subId);
 
+    // Not oneway, caller needs to make sure the vaule is set before receiving a SMS
+    void enableVisualVoicemailSmsFilter(String callingPackage, int subId,
+            in VisualVoicemailSmsFilterSettings settings);
+
+    oneway void disableVisualVoicemailSmsFilter(String callingPackage, int subId);
+
+    // Get settings set by the calling package
+    VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String callingPackage,
+            int subId);
+
+    // Get settings set by the package, requires READ_PRIVILEGED_PHONE_STATE permission
+    VisualVoicemailSmsFilterSettings getSystemVisualVoicemailSmsFilterSettings(String packageName,
+            int subId);
+
     /**
      * Returns the network type for data transmission
      * Legacy call, permission-free
@@ -1067,4 +1085,69 @@
      * Returns a list of packages that have carrier privileges.
      */
     List<String> getPackagesWithCarrierPrivileges();
+
+    /**
+     * Return the application ID for the app type.
+     *
+     * @param subId the subscription ID that this request applies to.
+     * @param appType the uicc app type,
+     * @return Application ID for specificied app type or null if no uicc or error.
+     */
+    String getAidForAppType(int subId, int appType);
+
+    /**
+    * Return the Electronic Serial Number.
+    *
+    * Requires that the calling app has READ_PRIVILEGED_PHONE_STATE permission
+    *
+    * @param subId the subscription ID that this request applies to.
+    * @return ESN or null if error.
+    * @hide
+    */
+    String getEsn(int subId);
+
+    /**
+     * Get snapshot of Telephony histograms
+     * @return List of Telephony histograms
+     * Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges.
+     */
+    List<TelephonyHistogram> getTelephonyHistograms();
+
+    /**
+     * Set the allowed carrier list for slotId
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return The number of carriers set successfully. Should match length of
+     * carriers on success.
+     */
+    int setAllowedCarriers(int slotId, in List<CarrierIdentifier> carriers);
+
+    /**
+     * Get the allowed carrier list for slotId.
+     * Require system privileges. In the future we may add this to carrier APIs.
+     *
+     * @return List of {@link android.service.carrier.CarrierIdentifier}; empty list
+     * means all carriers are allowed.
+     */
+    List<CarrierIdentifier> getAllowedCarriers(int slotId);
+
+   /**
+    * Action set from carrier signalling broadcast receivers to enable/disable metered apns
+    * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+    * @param subId the subscription ID that this action applies to.
+    * @param enabled control enable or disable metered apns.
+    * @hide
+    */
+    void carrierActionSetMeteredApnsEnabled(int subId, boolean visible);
+
+    /**
+     * Action set from carrier signalling broadcast receivers to enable/disable radio
+     * Permissions android.Manifest.permission.MODIFY_PHONE_STATE is required
+     * @param subId the subscription ID that this action applies to.
+     * @param enabled control enable or disable radio.
+     * @hide
+     */
+    void carrierActionSetRadioEnabled(int subId, boolean enabled);
 }
diff --git a/telephony/java/com/android/internal/telephony/IccCardConstants.java b/telephony/java/com/android/internal/telephony/IccCardConstants.java
index c1e2518..f3d9335 100644
--- a/telephony/java/com/android/internal/telephony/IccCardConstants.java
+++ b/telephony/java/com/android/internal/telephony/IccCardConstants.java
@@ -32,6 +32,8 @@
     public static final String INTENT_VALUE_ICC_ABSENT = "ABSENT";
     /* CARD_IO_ERROR means for three consecutive times there was SIM IO error */
     static public final String INTENT_VALUE_ICC_CARD_IO_ERROR = "CARD_IO_ERROR";
+    /* CARD_RESTRICTED means card is present but not usable due to carrier restrictions */
+    static public final String INTENT_VALUE_ICC_CARD_RESTRICTED = "CARD_RESTRICTED";
     /* LOCKED means ICC is locked by pin or by network */
     public static final String INTENT_VALUE_ICC_LOCKED = "LOCKED";
     //TODO: we can remove this state in the future if Bug 18489776 analysis
@@ -74,7 +76,8 @@
         READY,          /** ordinal(5) == {@See TelephonyManager#SIM_STATE_READY} */
         NOT_READY,      /** ordinal(6) == {@See TelephonyManager#SIM_STATE_NOT_READY} */
         PERM_DISABLED,  /** ordinal(7) == {@See TelephonyManager#SIM_STATE_PERM_DISABLED} */
-        CARD_IO_ERROR;  /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */
+        CARD_IO_ERROR,  /** ordinal(8) == {@See TelephonyManager#SIM_STATE_CARD_IO_ERROR} */
+        CARD_RESTRICTED;/** ordinal(9) == {@See TelephonyManager#SIM_STATE_CARD_RESTRICTED} */
 
         public boolean isPinLocked() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED));
@@ -83,7 +86,8 @@
         public boolean iccCardExist() {
             return ((this == PIN_REQUIRED) || (this == PUK_REQUIRED)
                     || (this == NETWORK_LOCKED) || (this == READY)
-                    || (this == PERM_DISABLED) || (this == CARD_IO_ERROR));
+                    || (this == PERM_DISABLED) || (this == CARD_IO_ERROR)
+                    || (this == CARD_RESTRICTED));
         }
 
         public static State intToState(int state) throws IllegalArgumentException {
@@ -97,6 +101,7 @@
                 case 6: return NOT_READY;
                 case 7: return PERM_DISABLED;
                 case 8: return CARD_IO_ERROR;
+                case 9: return CARD_RESTRICTED;
                 default:
                     throw new IllegalArgumentException();
             }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index cfc5305..a91e9beb 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -409,6 +409,8 @@
     int RIL_REQUEST_STOP_LCE = 133;
     int RIL_REQUEST_PULL_LCEDATA = 134;
     int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
+    int RIL_REQUEST_SET_ALLOWED_CARRIERS = 136;
+    int RIL_REQUEST_GET_ALLOWED_CARRIERS = 137;
 
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
 
@@ -459,4 +461,5 @@
     int RIL_UNSOL_ON_SS = 1043;
     int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
     int RIL_UNSOL_LCEDATA_RECV = 1045;
+    int RIL_UNSOL_PCO_DATA = 1046;
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 46b0fbd..49a7672 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -402,34 +402,54 @@
     /**
      * <p>Broadcast Action: when data connections get redirected with validation failure.
      * intended for sim/account status checks and only sent to the specified carrier app
-     * feedback is via carrier/system APIs to report cold-sim, out-of-credit-sim, etc
      * The intent will have the following extra values:</p>
      * <ul>
-     *   <li>redirectUrl</li><dd>A string with the redirection url info.</dd>
-     *   <li>subId</li><dd>Sub Id which associated the data redirection.</dd>
+     *   <li>apnType</li><dd>A string with the apn type.</dd>
+     *   <li>redirectionUrl</li><dd>redirection url string</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system.</p>
      */
-    public static final String ACTION_DATA_CONNECTION_REDIRECTED =
-            "android.intent.action.REDIRECTION_DETECTED";
+    public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
+            "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
     /**
      * <p>Broadcast Action: when data connections setup fails.
      * intended for sim/account status checks and only sent to the specified carrier app
-     * feedback is via carrier/system APIs to report cold-sim, out-of-credit-sim, etc
      * The intent will have the following extra values:</p>
      * <ul>
      *   <li>apnType</li><dd>A string with the apn type.</dd>
      *   <li>errorCode</li><dd>A integer with dataFailCause.</dd>
-     *   <li>subId</dt><li>Sub Id which associated the data redirection.</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
-    public static final String ACTION_REQUEST_NETWORK_FAILED =
-            "android.intent.action.REQUEST_NETWORK_FAILED";
+    public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
+            "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
 
     /**
-     * Broadcast action to trigger CI OMA-DM Session.
+     * <p>Broadcast Action: when pco value is available.
+     * intended for sim/account status checks and only sent to the specified carrier app
+     * The intent will have the following extra values:</p>
+     * <ul>
+     *   <li>apnType</li><dd>A string with the apn type.</dd>
+     *   <li>pcoValue</li><dd>A integer read from modem.</dd>
+     *   <li>subId</dt><li>Sub Id which associated the data connection.</dd>
+     * </ul>
+     * <p class="note">This is a protected intent that can only be sent by the system. </p>
      */
+    public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
+            "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+
+    // CARRIER_SIGNAL_ACTION extra keys
+    public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
+    public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
+    public static final String EXTRA_APN_TYPE_KEY = "apnType";
+    public static final String EXTRA_PCO_KEY = "pco";
+
+
+   /**
+     * Broadcast action to trigger CI OMA-DM Session.
+    */
     public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
             "com.android.omadm.service.CONFIGURATION_UPDATE";
 }
diff --git a/tests/WallpaperTest/res/values/strings.xml b/tests/WallpaperTest/res/values/strings.xml
index fd21259..80a3d49 100644
--- a/tests/WallpaperTest/res/values/strings.xml
+++ b/tests/WallpaperTest/res/values/strings.xml
@@ -24,6 +24,9 @@
         Test wallpaper for use with the wallpaper test app.
     </string>
 
+    <string name="test_wallpaper_context_uri">https://www.google.com/maps/@37.8092876,-122.408986,1391m/data=!3m1!1e3</string>
+    <string name="test_wallpaper_context_description">Explore</string>
+
     <string name="dimens">Dimens: </string>
     <string name="width">Width: </string>
     <string name="height">Height: </string>
diff --git a/tests/WallpaperTest/res/xml/test_wallpaper.xml b/tests/WallpaperTest/res/xml/test_wallpaper.xml
index 9f7d714b..ba22478 100644
--- a/tests/WallpaperTest/res/xml/test_wallpaper.xml
+++ b/tests/WallpaperTest/res/xml/test_wallpaper.xml
@@ -23,4 +23,7 @@
 <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"
     android:author="@string/test_wallpaper_author"
     android:description="@string/test_wallpaper_desc"
-    android:thumbnail="@drawable/test_wallpaper_thumb" />
+    android:thumbnail="@drawable/test_wallpaper_thumb"
+    android:showMetadataInPreview="true"
+    android:contextUri="@string/test_wallpaper_context_uri"
+    android:contextDescription="@string/test_wallpaper_context_description"/>
diff --git a/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java b/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java
index 95db6d1..ab36c22 100644
--- a/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java
+++ b/tests/WallpaperTest/src/com/example/wallpapertest/TestWallpaper.java
@@ -144,6 +144,14 @@
         @Override
         public void onSurfaceCreated(SurfaceHolder holder) {
             super.onSurfaceCreated(holder);
+
+            // Simulate some slowness, so we can test the loading process in the live wallpaper
+            // picker.
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
         }
 
         @Override
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
index 3a1e2bb..4b5ea65 100644
--- a/tools/aapt2/Android.mk
+++ b/tools/aapt2/Android.mk
@@ -115,6 +115,7 @@
 
 toolSources := \
 	compile/Compile.cpp \
+	diff/Diff.cpp \
 	dump/Dump.cpp \
 	link/Link.cpp
 
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index a2fadd9..00d8aae 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -24,6 +24,7 @@
 extern int compile(const std::vector<StringPiece>& args);
 extern int link(const std::vector<StringPiece>& args);
 extern int dump(const std::vector<StringPiece>& args);
+extern int diff(const std::vector<StringPiece>& args);
 
 } // namespace aapt
 
@@ -44,12 +45,14 @@
             return aapt::link(args);
         } else if (command == "dump" || command == "d") {
             return aapt::dump(args);
+        } else if (command == "diff") {
+            return aapt::diff(args);
         }
         std::cerr << "unknown command '" << command << "'\n";
     } else {
         std::cerr << "no command specified\n";
     }
 
-    std::cerr << "\nusage: aapt2 [compile|link|dump] ..." << std::endl;
+    std::cerr << "\nusage: aapt2 [compile|link|dump|diff] ..." << std::endl;
     return 1;
 }
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 9704d970..a84c306 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -152,7 +152,7 @@
                 break;
             }
 
-            spanStack.back().lastChar = builder.str().size();
+            spanStack.back().lastChar = builder.str().size() - 1;
             outStyleString->spans.push_back(spanStack.back());
             spanStack.pop_back();
 
@@ -1058,6 +1058,16 @@
 
     std::unique_ptr<Array> array = util::make_unique<Array>();
 
+    bool translateable = mOptions.translatable;
+    if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) {
+        if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) {
+            mDiag->error(DiagMessage(outResource->source)
+                         << "invalid value for 'translatable'. Must be a boolean");
+            return false;
+        }
+    }
+    array->setTranslateable(translateable);
+
     bool error = false;
     const size_t depth = parser->getDepth();
     while (xml::XmlPullParser::nextChildNode(parser, depth)) {
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 8d734f3..e700ed9 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -189,6 +189,17 @@
     return results;
 }
 
+std::vector<ResourceConfigValue*> ResourceEntry::findValuesIf(
+        const std::function<bool(ResourceConfigValue*)>& f) {
+    std::vector<ResourceConfigValue*> results;
+    for (auto& configValue : values) {
+        if (f(configValue.get())) {
+            results.push_back(configValue.get());
+        }
+    }
+    return results;
+}
+
 /**
  * The default handler for collisions. A return value of -1 means keep the
  * existing value, 0 means fail, and +1 means take the incoming value.
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index 7f5c2b8..5690ea6 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -26,6 +26,7 @@
 #include "io/File.h"
 
 #include <android-base/macros.h>
+#include <functional>
 #include <map>
 #include <memory>
 #include <string>
@@ -109,6 +110,9 @@
     ResourceConfigValue* findOrCreateValue(const ConfigDescription& config,
                                            const StringPiece& product);
     std::vector<ResourceConfigValue*> findAllValues(const ConfigDescription& config);
+    std::vector<ResourceConfigValue*> findValuesIf(
+            const std::function<bool(ResourceConfigValue*)>& f);
+
 
 private:
     DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 74c48b0..a0a7efc 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -289,7 +289,7 @@
 std::unique_ptr<BinaryPrimitive> tryParseFlagSymbol(const Attribute* flagAttr,
                                                     const StringPiece16& str) {
     android::Res_value flags = { };
-    flags.dataType = android::Res_value::TYPE_INT_DEC;
+    flags.dataType = android::Res_value::TYPE_INT_HEX;
     flags.data = 0u;
 
     if (util::trimWhitespace(str).empty()) {
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index dd7ff01..c10b134 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -39,6 +39,14 @@
 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
 }
 
+bool RawString::equals(const Value* value) const {
+    const RawString* other = valueCast<RawString>(value);
+    if (!other) {
+        return false;
+    }
+    return *this->value == *other->value;
+}
+
 RawString* RawString::clone(StringPool* newPool) const {
     RawString* rs = new RawString(newPool->makeRef(*value));
     rs->mComment = mComment;
@@ -66,6 +74,15 @@
 Reference::Reference(const ResourceId& i, Type type) : id(i), referenceType(type) {
 }
 
+bool Reference::equals(const Value* value) const {
+    const Reference* other = valueCast<Reference>(value);
+    if (!other) {
+        return false;
+    }
+    return referenceType == other->referenceType && privateReference == other->privateReference &&
+            id == other->id && name == other->name;
+}
+
 bool Reference::flatten(android::Res_value* outValue) const {
     outValue->dataType = (referenceType == Reference::Type::kResource) ?
             android::Res_value::TYPE_REFERENCE : android::Res_value::TYPE_ATTRIBUTE;
@@ -97,6 +114,10 @@
     }
 }
 
+bool Id::equals(const Value* value) const {
+    return valueCast<Id>(value) != nullptr;
+}
+
 bool Id::flatten(android::Res_value* out) const {
     out->dataType = android::Res_value::TYPE_INT_BOOLEAN;
     out->data = util::hostToDevice32(0);
@@ -111,15 +132,15 @@
     *out << "(id)";
 }
 
-String::String(const StringPool::Ref& ref) : value(ref), mTranslateable(true) {
+String::String(const StringPool::Ref& ref) : value(ref) {
 }
 
-void String::setTranslateable(bool val) {
-    mTranslateable = val;
-}
-
-bool String::isTranslateable() const {
-    return mTranslateable;
+bool String::equals(const Value* value) const {
+    const String* other = valueCast<String>(value);
+    if (!other) {
+        return false;
+    }
+    return *this->value == *other->value;
 }
 
 bool String::flatten(android::Res_value* outValue) const {
@@ -144,15 +165,24 @@
     *out << "(string) \"" << *value << "\"";
 }
 
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) {
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
 }
 
-void StyledString::setTranslateable(bool val) {
-    mTranslateable = val;
-}
+bool StyledString::equals(const Value* value) const {
+    const StyledString* other = valueCast<StyledString>(value);
+    if (!other) {
+        return false;
+    }
 
-bool StyledString::isTranslateable() const {
-    return mTranslateable;
+    if (*this->value->str == *other->value->str) {
+        const std::vector<StringPool::Span>& spansA = this->value->spans;
+        const std::vector<StringPool::Span>& spansB = other->value->spans;
+        return std::equal(spansA.begin(), spansA.end(), spansB.begin(),
+                          [](const StringPool::Span& a, const StringPool::Span& b) -> bool {
+            return *a.name == *b.name && a.firstChar == b.firstChar && a.lastChar == b.lastChar;
+        });
+    }
+    return false;
 }
 
 bool StyledString::flatten(android::Res_value* outValue) const {
@@ -174,11 +204,22 @@
 
 void StyledString::print(std::ostream* out) const {
     *out << "(styled string) \"" << *value->str << "\"";
+    for (const StringPool::Span& span : value->spans) {
+        *out << " "<< *span.name << ":" << span.firstChar << "," << span.lastChar;
+    }
 }
 
 FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
 }
 
+bool FileReference::equals(const Value* value) const {
+    const FileReference* other = valueCast<FileReference>(value);
+    if (!other) {
+        return false;
+    }
+    return *path == *other->path;
+}
+
 bool FileReference::flatten(android::Res_value* outValue) const {
     if (path.getIndex() > std::numeric_limits<uint32_t>::max()) {
         return false;
@@ -209,6 +250,14 @@
     value.data = data;
 }
 
+bool BinaryPrimitive::equals(const Value* value) const {
+    const BinaryPrimitive* other = valueCast<BinaryPrimitive>(value);
+    if (!other) {
+        return false;
+    }
+    return this->value.dataType == other->value.dataType && this->value.data == other->value.data;
+}
+
 bool BinaryPrimitive::flatten(android::Res_value* outValue) const {
     outValue->dataType = value.dataType;
     outValue->data = util::hostToDevice32(value.data);
@@ -228,7 +277,7 @@
             *out << "(integer) " << static_cast<int32_t>(value.data);
             break;
         case android::Res_value::TYPE_INT_HEX:
-            *out << "(integer) " << std::hex << value.data << std::dec;
+            *out << "(integer) 0x" << std::hex << value.data << std::dec;
             break;
         case android::Res_value::TYPE_INT_BOOLEAN:
             *out << "(boolean) " << (value.data != 0 ? "true" : "false");
@@ -253,6 +302,21 @@
     mWeak = w;
 }
 
+bool Attribute::equals(const Value* value) const {
+    const Attribute* other = valueCast<Attribute>(value);
+    if (!other) {
+        return false;
+    }
+
+    return this->typeMask == other->typeMask && this->minInt == other->minInt &&
+            this->maxInt == other->maxInt &&
+            std::equal(this->symbols.begin(), this->symbols.end(),
+                       other->symbols.begin(),
+                       [](const Symbol& a, const Symbol& b) -> bool {
+        return a.symbol.equals(&b.symbol) && a.value == b.value;
+    });
+}
+
 Attribute* Attribute::clone(StringPool* /*newPool*/) const {
     return new Attribute(*this);
 }
@@ -365,6 +429,14 @@
             << "]";
     }
 
+    if (minInt != std::numeric_limits<int32_t>::min()) {
+        *out << " min=" << minInt;
+    }
+
+    if (maxInt != std::numeric_limits<int32_t>::max()) {
+        *out << " max=" << maxInt;
+    }
+
     if (isWeak()) {
         *out << " [weak]";
     }
@@ -445,6 +517,21 @@
     return true;
 }
 
+bool Style::equals(const Value* value) const {
+    const Style* other = valueCast<Style>(value);
+    if (!other) {
+        return false;
+    }
+    if (bool(parent) != bool(other->parent) ||
+            (parent && other->parent && !parent.value().equals(&other->parent.value()))) {
+        return false;
+    }
+    return std::equal(entries.begin(), entries.end(), other->entries.begin(),
+                      [](const Entry& a, const Entry& b) -> bool {
+        return a.key.equals(&b.key) && a.value->equals(b.value.get());
+    });
+}
+
 Style* Style::clone(StringPool* newPool) const {
     Style* style = new Style();
     style->parent = parent;
@@ -484,6 +571,18 @@
     return out;
 }
 
+bool Array::equals(const Value* value) const {
+    const Array* other = valueCast<Array>(value);
+    if (!other) {
+        return false;
+    }
+
+    return std::equal(items.begin(), items.end(), other->items.begin(),
+                      [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
+        return a->equals(b.get());
+    });
+}
+
 Array* Array::clone(StringPool* newPool) const {
     Array* array = new Array();
     array->mComment = mComment;
@@ -500,6 +599,21 @@
         << "]";
 }
 
+bool Plural::equals(const Value* value) const {
+    const Plural* other = valueCast<Plural>(value);
+    if (!other) {
+        return false;
+    }
+
+    return std::equal(values.begin(), values.end(), other->values.begin(),
+                      [](const std::unique_ptr<Item>& a, const std::unique_ptr<Item>& b) -> bool {
+        if (bool(a) != bool(b)) {
+            return false;
+        }
+        return bool(a) == bool(b) || a->equals(b.get());
+    });
+}
+
 Plural* Plural::clone(StringPool* newPool) const {
     Plural* p = new Plural();
     p->mComment = mComment;
@@ -515,12 +629,42 @@
 
 void Plural::print(std::ostream* out) const {
     *out << "(plural)";
+    if (values[Zero]) {
+        *out << " zero=" << *values[Zero];
+    }
+
+    if (values[One]) {
+        *out << " one=" << *values[One];
+    }
+
+    if (values[Two]) {
+        *out << " two=" << *values[Two];
+    }
+
+    if (values[Few]) {
+        *out << " few=" << *values[Few];
+    }
+
+    if (values[Many]) {
+        *out << " many=" << *values[Many];
+    }
 }
 
 static ::std::ostream& operator<<(::std::ostream& out, const std::unique_ptr<Item>& item) {
     return out << *item;
 }
 
+bool Styleable::equals(const Value* value) const {
+    const Styleable* other = valueCast<Styleable>(value);
+    if (!other) {
+        return false;
+    }
+    return std::equal(entries.begin(), entries.end(), other->entries.begin(),
+                      [](const Reference& a, const Reference& b) -> bool {
+        return a.equals(&b);
+    });
+}
+
 Styleable* Styleable::clone(StringPool* /*newPool*/) const {
     return new Styleable(*this);
 }
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 43354ac..aa1b550 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -54,6 +54,18 @@
         mWeak = val;
     }
 
+    // Whether the value is marked as translateable.
+    // This does not persist when flattened.
+    // It is only used during compilation phase.
+    void setTranslateable(bool val) {
+        mTranslateable = val;
+    }
+
+    // Default true.
+    bool isTranslateable() const {
+        return mTranslateable;
+    }
+
     /**
      * Returns the source where this value was defined.
      */
@@ -84,6 +96,8 @@
         mComment = std::move(str);
     }
 
+    virtual bool equals(const Value* value) const = 0;
+
     /**
      * Calls the appropriate overload of ValueVisitor.
      */
@@ -103,6 +117,7 @@
     Source mSource;
     std::u16string mComment;
     bool mWeak = false;
+    bool mTranslateable = true;
 };
 
 /**
@@ -158,6 +173,7 @@
     explicit Reference(const ResourceNameRef& n, Type type = Type::kResource);
     explicit Reference(const ResourceId& i, Type type = Type::kResource);
 
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     Reference* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -168,6 +184,7 @@
  */
 struct Id : public BaseItem<Id> {
     Id() { mWeak = true; }
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* out) const override;
     Id* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -183,6 +200,7 @@
 
     RawString(const StringPool::Ref& ref);
 
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     RawString* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -193,17 +211,10 @@
 
     String(const StringPool::Ref& ref);
 
-    // Whether the string is marked as translateable. This does not persist when flattened.
-    // It is only used during compilation phase.
-    void setTranslateable(bool val);
-    bool isTranslateable() const;
-
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     String* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
-
-private:
-    bool mTranslateable;
 };
 
 struct StyledString : public BaseItem<StyledString> {
@@ -211,17 +222,10 @@
 
     StyledString(const StringPool::StyleRef& ref);
 
-    // Whether the string is marked as translateable. This does not persist when flattened.
-    // It is only used during compilation phase.
-    void setTranslateable(bool val);
-    bool isTranslateable() const;
-
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     StyledString* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
-
-private:
-    bool mTranslateable;
 };
 
 struct FileReference : public BaseItem<FileReference> {
@@ -235,6 +239,7 @@
     FileReference() = default;
     FileReference(const StringPool::Ref& path);
 
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     FileReference* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -250,6 +255,7 @@
     BinaryPrimitive(const android::Res_value& val);
     BinaryPrimitive(uint8_t dataType, uint32_t data);
 
+    bool equals(const Value* value) const override;
     bool flatten(android::Res_value* outValue) const override;
     BinaryPrimitive* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
@@ -268,6 +274,7 @@
 
     Attribute(bool w, uint32_t t = 0u);
 
+    bool equals(const Value* value) const override;
     Attribute* clone(StringPool* newPool) const override;
     void printMask(std::ostream* out) const;
     void print(std::ostream* out) const override;
@@ -290,6 +297,7 @@
 
     std::vector<Entry> entries;
 
+    bool equals(const Value* value) const override;
     Style* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
 };
@@ -297,6 +305,7 @@
 struct Array : public BaseValue<Array> {
     std::vector<std::unique_ptr<Item>> items;
 
+    bool equals(const Value* value) const override;
     Array* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
 };
@@ -314,6 +323,7 @@
 
     std::array<std::unique_ptr<Item>, Count> values;
 
+    bool equals(const Value* value) const override;
     Plural* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
 };
@@ -321,6 +331,7 @@
 struct Styleable : public BaseValue<Styleable> {
     std::vector<Reference> entries;
 
+    bool equals(const Value* value) const override;
     Styleable* clone(StringPool* newPool) const override;
     void print(std::ostream* out) const override;
 };
diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h
index ea2aa55..b8bc5db 100644
--- a/tools/aapt2/ValueVisitor.h
+++ b/tools/aapt2/ValueVisitor.h
@@ -127,6 +127,11 @@
     }
 };
 
+template <typename T>
+const T* valueCast(const Value* value) {
+    return valueCast<T>(const_cast<Value*>(value));
+}
+
 /**
  * Returns a valid pointer to T if the Value is of subtype T.
  * Otherwise, returns nullptr.
@@ -141,7 +146,6 @@
     return visitor.value;
 }
 
-
 inline void visitAllValuesInPackage(ResourceTablePackage* pkg, RawValueVisitor* visitor) {
     for (auto& type : pkg->types) {
         for (auto& entry : type->entries) {
diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp
index 99c2077..d080e16 100644
--- a/tools/aapt2/compile/PseudolocaleGenerator.cpp
+++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp
@@ -128,23 +128,6 @@
             mPool(pool), mMethod(method), mLocalizer(method) {
     }
 
-    void visit(Array* array) override {
-        std::unique_ptr<Array> localized = util::make_unique<Array>();
-        localized->items.resize(array->items.size());
-        for (size_t i = 0; i < array->items.size(); i++) {
-            Visitor subVisitor(mPool, mMethod);
-            array->items[i]->accept(&subVisitor);
-            if (subVisitor.mItem) {
-                localized->items[i] = std::move(subVisitor.mItem);
-            } else {
-                localized->items[i] = std::unique_ptr<Item>(array->items[i]->clone(mPool));
-            }
-        }
-        localized->setSource(array->getSource());
-        localized->setWeak(true);
-        mValue = std::move(localized);
-    }
-
     void visit(Plural* plural) override {
         std::unique_ptr<Plural> localized = util::make_unique<Plural>();
         for (size_t i = 0; i < plural->values.size(); i++) {
@@ -164,10 +147,6 @@
     }
 
     void visit(String* string) override {
-        if (!string->isTranslateable()) {
-            return;
-        }
-
         std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) +
                 mLocalizer.end();
         std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result));
@@ -177,10 +156,6 @@
     }
 
     void visit(StyledString* string) override {
-        if (!string->isTranslateable()) {
-            return;
-        }
-
         mItem = pseudolocalizeStyledString(string, mMethod, mPool);
         mItem->setWeak(true);
     }
@@ -238,14 +213,26 @@
     }
 }
 
+/**
+ * A value is pseudolocalizable if it does not define a locale (or is the default locale)
+ * and is translateable.
+ */
+static bool isPseudolocalizable(ResourceConfigValue* configValue) {
+    const int diff = configValue->config.diff(ConfigDescription::defaultConfig());
+    if (diff & ConfigDescription::CONFIG_LOCALE) {
+        return false;
+    }
+    return configValue->value->isTranslateable();
+}
+
 } // namespace
 
 bool PseudolocaleGenerator::consume(IAaptContext* context, ResourceTable* table) {
     for (auto& package : table->packages) {
         for (auto& type : package->types) {
             for (auto& entry : type->entries) {
-                std::vector<ResourceConfigValue*> values = entry->findAllValues(
-                        ConfigDescription::defaultConfig());
+                std::vector<ResourceConfigValue*> values = entry->findValuesIf(isPseudolocalizable);
+
                 for (ResourceConfigValue* value : values) {
                     pseudolocalizeIfNeeded(Pseudolocalizer::Method::kAccent, value,
                                            &table->stringPool, entry.get());
diff --git a/tools/aapt2/diff/Diff.cpp b/tools/aapt2/diff/Diff.cpp
new file mode 100644
index 0000000..20b7b59
--- /dev/null
+++ b/tools/aapt2/diff/Diff.cpp
@@ -0,0 +1,411 @@
+/*
+ * 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 "Flags.h"
+#include "ResourceTable.h"
+#include "io/ZipArchive.h"
+#include "process/IResourceTableConsumer.h"
+#include "process/SymbolTable.h"
+#include "unflatten/BinaryResourceParser.h"
+
+#include <android-base/macros.h>
+
+namespace aapt {
+
+class DiffContext : public IAaptContext {
+public:
+    const std::u16string& getCompilationPackage() override {
+        return mEmpty;
+    }
+
+    uint8_t getPackageId() override {
+        return 0x0;
+    }
+
+    IDiagnostics* getDiagnostics() override {
+        return &mDiagnostics;
+    }
+
+    NameMangler* getNameMangler() override {
+        return &mNameMangler;
+    }
+
+    SymbolTable* getExternalSymbols() override {
+        return &mSymbolTable;
+    }
+
+    bool verbose() override {
+        return false;
+    }
+
+private:
+    std::u16string mEmpty;
+    StdErrDiagnostics mDiagnostics;
+    NameMangler mNameMangler = NameMangler(NameManglerPolicy{});
+    SymbolTable mSymbolTable;
+};
+
+class LoadedApk {
+public:
+    LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+              std::unique_ptr<ResourceTable> table) :
+            mSource(source), mApk(std::move(apk)), mTable(std::move(table)) {
+    }
+
+    io::IFileCollection* getFileCollection() {
+        return mApk.get();
+    }
+
+    ResourceTable* getResourceTable() {
+        return mTable.get();
+    }
+
+    const Source& getSource() {
+        return mSource;
+    }
+
+private:
+    Source mSource;
+    std::unique_ptr<io::IFileCollection> mApk;
+    std::unique_ptr<ResourceTable> mTable;
+
+    DISALLOW_COPY_AND_ASSIGN(LoadedApk);
+};
+
+static std::unique_ptr<LoadedApk> loadApkFromPath(IAaptContext* context, const StringPiece& path) {
+    Source source(path);
+    std::string error;
+    std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::create(path, &error);
+    if (!apk) {
+        context->getDiagnostics()->error(DiagMessage(source) << error);
+        return {};
+    }
+
+    io::IFile* file = apk->findFile("resources.arsc");
+    if (!file) {
+        context->getDiagnostics()->error(DiagMessage(source) << "no resources.arsc found");
+        return {};
+    }
+
+    std::unique_ptr<io::IData> data = file->openAsData();
+    if (!data) {
+        context->getDiagnostics()->error(DiagMessage(source) << "could not open resources.arsc");
+        return {};
+    }
+
+    std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+    BinaryResourceParser parser(context, table.get(), source, data->data(), data->size());
+    if (!parser.parse()) {
+        return {};
+    }
+
+    return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
+}
+
+static void emitDiffLine(const Source& source, const StringPiece& message) {
+    std::cerr << source << ": " << message << "\n";
+}
+
+static bool isSymbolVisibilityDifferent(const Symbol& symbolA, const Symbol& symbolB) {
+    return symbolA.state != symbolB.state;
+}
+
+template <typename Id>
+static bool isIdDiff(const Symbol& symbolA, const Maybe<Id>& idA,
+                     const Symbol& symbolB, const Maybe<Id>& idB) {
+    if (symbolA.state == SymbolState::kPublic || symbolB.state == SymbolState::kPublic) {
+        return idA != idB;
+    }
+    return false;
+}
+
+static bool emitResourceConfigValueDiff(IAaptContext* context,
+                                        LoadedApk* apkA,
+                                        ResourceTablePackage* pkgA,
+                                        ResourceTableType* typeA,
+                                        ResourceEntry* entryA,
+                                        ResourceConfigValue* configValueA,
+                                        LoadedApk* apkB,
+                                        ResourceTablePackage* pkgB,
+                                        ResourceTableType* typeB,
+                                        ResourceEntry* entryB,
+                                        ResourceConfigValue* configValueB) {
+    Value* valueA = configValueA->value.get();
+    Value* valueB = configValueB->value.get();
+    if (!valueA->equals(valueB)) {
+        std::stringstream strStream;
+        strStream << "value " << pkgA->name << ":" << typeA->type << "/" << entryA->name
+                << " config=" << configValueA->config << " does not match:\n";
+        valueA->print(&strStream);
+        strStream << "\n vs \n";
+        valueB->print(&strStream);
+        emitDiffLine(apkB->getSource(), strStream.str());
+        return true;
+    }
+    return false;
+}
+
+static bool emitResourceEntryDiff(IAaptContext* context,
+                                  LoadedApk* apkA,
+                                  ResourceTablePackage* pkgA,
+                                  ResourceTableType* typeA,
+                                  ResourceEntry* entryA,
+                                  LoadedApk* apkB,
+                                  ResourceTablePackage* pkgB,
+                                  ResourceTableType* typeB,
+                                  ResourceEntry* entryB) {
+    bool diff = false;
+    for (std::unique_ptr<ResourceConfigValue>& configValueA : entryA->values) {
+        ResourceConfigValue* configValueB = entryB->findValue(configValueA->config);
+        if (!configValueB) {
+            std::stringstream strStream;
+            strStream << "missing " << pkgA->name << ":" << typeA->type << "/" << entryA->name
+                    << " config=" << configValueA->config;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        } else {
+            diff |= emitResourceConfigValueDiff(context, apkA, pkgA, typeA, entryA,
+                                                configValueA.get(), apkB, pkgB, typeB, entryB,
+                                                configValueB);
+        }
+    }
+
+    // Check for any newly added config values.
+    for (std::unique_ptr<ResourceConfigValue>& configValueB : entryB->values) {
+        ResourceConfigValue* configValueA = entryA->findValue(configValueB->config);
+        if (!configValueA) {
+            std::stringstream strStream;
+            strStream << "new config " << pkgB->name << ":" << typeB->type << "/" << entryB->name
+                    << " config=" << configValueB->config;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        }
+    }
+    return false;
+}
+
+static bool emitResourceTypeDiff(IAaptContext* context,
+                                 LoadedApk* apkA,
+                                 ResourceTablePackage* pkgA,
+                                 ResourceTableType* typeA,
+                                 LoadedApk* apkB,
+                                 ResourceTablePackage* pkgB,
+                                 ResourceTableType* typeB) {
+    bool diff = false;
+    for (std::unique_ptr<ResourceEntry>& entryA : typeA->entries) {
+        ResourceEntry* entryB = typeB->findEntry(entryA->name);
+        if (!entryB) {
+            std::stringstream strStream;
+            strStream << "missing " << pkgA->name << ":" << typeA->type << "/" << entryA->name;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        } else {
+            if (isSymbolVisibilityDifferent(entryA->symbolStatus, entryB->symbolStatus)) {
+                std::stringstream strStream;
+                strStream << pkgA->name << ":" << typeA->type << "/" << entryA->name
+                        << " has different visibility (";
+                if (entryB->symbolStatus.state == SymbolState::kPublic) {
+                    strStream << "PUBLIC";
+                } else {
+                    strStream << "PRIVATE";
+                }
+                strStream << " vs ";
+                if (entryA->symbolStatus.state == SymbolState::kPublic) {
+                    strStream << "PUBLIC";
+                } else {
+                    strStream << "PRIVATE";
+                }
+                strStream << ")";
+                emitDiffLine(apkB->getSource(), strStream.str());
+                diff = true;
+            } else if (isIdDiff(entryA->symbolStatus, entryA->id,
+                                entryB->symbolStatus, entryB->id)) {
+                std::stringstream strStream;
+                strStream << pkgA->name << ":" << typeA->type << "/" << entryA->name
+                        << " has different public ID (";
+                if (entryB->id) {
+                    strStream << "0x" << std::hex << entryB->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << " vs ";
+                if (entryA->id) {
+                    strStream << "0x " << std::hex << entryA->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << ")";
+                emitDiffLine(apkB->getSource(), strStream.str());
+                diff = true;
+            }
+            diff |= emitResourceEntryDiff(context, apkA, pkgA, typeA, entryA.get(),
+                                          apkB, pkgB, typeB, entryB);
+        }
+    }
+
+    // Check for any newly added entries.
+    for (std::unique_ptr<ResourceEntry>& entryB : typeB->entries) {
+        ResourceEntry* entryA = typeA->findEntry(entryB->name);
+        if (!entryA) {
+            std::stringstream strStream;
+            strStream << "new entry " << pkgB->name << ":" << typeB->type << "/" << entryB->name;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        }
+    }
+    return diff;
+}
+
+static bool emitResourcePackageDiff(IAaptContext* context, LoadedApk* apkA,
+                                    ResourceTablePackage* pkgA,
+                                    LoadedApk* apkB, ResourceTablePackage* pkgB) {
+    bool diff = false;
+    for (std::unique_ptr<ResourceTableType>& typeA : pkgA->types) {
+        ResourceTableType* typeB = pkgB->findType(typeA->type);
+        if (!typeB) {
+            std::stringstream strStream;
+            strStream << "missing " << pkgA->name << ":" << typeA->type;
+            emitDiffLine(apkA->getSource(), strStream.str());
+            diff = true;
+        } else {
+            if (isSymbolVisibilityDifferent(typeA->symbolStatus, typeB->symbolStatus)) {
+                std::stringstream strStream;
+                strStream << pkgA->name << ":" << typeA->type << " has different visibility (";
+                if (typeB->symbolStatus.state == SymbolState::kPublic) {
+                    strStream << "PUBLIC";
+                } else {
+                    strStream << "PRIVATE";
+                }
+                strStream << " vs ";
+                if (typeA->symbolStatus.state == SymbolState::kPublic) {
+                    strStream << "PUBLIC";
+                } else {
+                    strStream << "PRIVATE";
+                }
+                strStream << ")";
+                emitDiffLine(apkB->getSource(), strStream.str());
+                diff = true;
+            } else if (isIdDiff(typeA->symbolStatus, typeA->id, typeB->symbolStatus, typeB->id)) {
+                std::stringstream strStream;
+                strStream << pkgA->name << ":" << typeA->type << " has different public ID (";
+                if (typeB->id) {
+                    strStream << "0x" << std::hex << typeB->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << " vs ";
+                if (typeA->id) {
+                    strStream << "0x " << std::hex << typeA->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << ")";
+                emitDiffLine(apkB->getSource(), strStream.str());
+                diff = true;
+            }
+            diff |= emitResourceTypeDiff(context, apkA, pkgA, typeA.get(), apkB, pkgB, typeB);
+        }
+    }
+
+    // Check for any newly added types.
+    for (std::unique_ptr<ResourceTableType>& typeB : pkgB->types) {
+        ResourceTableType* typeA = pkgA->findType(typeB->type);
+        if (!typeA) {
+            std::stringstream strStream;
+            strStream << "new type " << pkgB->name << ":" << typeB->type;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        }
+    }
+    return diff;
+}
+
+static bool emitResourceTableDiff(IAaptContext* context, LoadedApk* apkA, LoadedApk* apkB) {
+    ResourceTable* tableA = apkA->getResourceTable();
+    ResourceTable* tableB = apkB->getResourceTable();
+
+    bool diff = false;
+    for (std::unique_ptr<ResourceTablePackage>& pkgA : tableA->packages) {
+        ResourceTablePackage* pkgB = tableB->findPackage(pkgA->name);
+        if (!pkgB) {
+            std::stringstream strStream;
+            strStream << "missing package " << pkgA->name;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        } else {
+            if (pkgA->id != pkgB->id) {
+                std::stringstream strStream;
+                strStream << "package '" << pkgA->name << "' has different id (";
+                if (pkgB->id) {
+                    strStream << "0x" << std::hex << pkgB->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << " vs ";
+                if (pkgA->id) {
+                    strStream << "0x" << std::hex << pkgA->id.value();
+                } else {
+                    strStream << "none";
+                }
+                strStream << ")";
+                emitDiffLine(apkB->getSource(), strStream.str());
+                diff = true;
+            }
+            diff |= emitResourcePackageDiff(context, apkA, pkgA.get(), apkB, pkgB);
+        }
+    }
+
+    // Check for any newly added packages.
+    for (std::unique_ptr<ResourceTablePackage>& pkgB : tableB->packages) {
+        ResourceTablePackage* pkgA = tableA->findPackage(pkgB->name);
+        if (!pkgA) {
+            std::stringstream strStream;
+            strStream << "new package " << pkgB->name;
+            emitDiffLine(apkB->getSource(), strStream.str());
+            diff = true;
+        }
+    }
+    return diff;
+}
+
+int diff(const std::vector<StringPiece>& args) {
+    DiffContext context;
+
+    Flags flags;
+    if (!flags.parse("aapt2 diff", args, &std::cerr)) {
+        return 1;
+    }
+
+    if (flags.getArgs().size() != 2u) {
+        std::cerr << "must have two apks as arguments.\n\n";
+        flags.usage("aapt2 diff", &std::cerr);
+        return 1;
+    }
+
+    std::unique_ptr<LoadedApk> apkA = loadApkFromPath(&context, flags.getArgs()[0]);
+    std::unique_ptr<LoadedApk> apkB = loadApkFromPath(&context, flags.getArgs()[1]);
+    if (!apkA || !apkB) {
+        return 1;
+    }
+
+    if (emitResourceTableDiff(&context, apkA.get(), apkB.get())) {
+        // We emitted a diff, so return 1 (failure).
+        return 1;
+    }
+    return 0;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 953e87e..77a949f 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -180,7 +180,6 @@
 
     manifestAction[u"uses-configuration"];
     manifestAction[u"uses-feature"];
-    manifestAction[u"uses-library"];
     manifestAction[u"supports-screens"];
     manifestAction[u"compatible-screens"];
     manifestAction[u"supports-gl-texture"];
@@ -189,6 +188,9 @@
     xml::XmlNodeAction& applicationAction = (*executor)[u"manifest"][u"application"];
     applicationAction.action(optionalNameIsJavaClassName);
 
+    // Uses library actions.
+    applicationAction[u"uses-library"];
+
     // Activity actions.
     applicationAction[u"activity"].action(requiredNameIsJavaClassName);
     applicationAction[u"activity"][u"intent-filter"] = intentFilterAction;
diff --git a/tools/aapt2/proto/TableProtoDeserializer.cpp b/tools/aapt2/proto/TableProtoDeserializer.cpp
index 82e4fb0..1ec48f0 100644
--- a/tools/aapt2/proto/TableProtoDeserializer.cpp
+++ b/tools/aapt2/proto/TableProtoDeserializer.cpp
@@ -234,6 +234,8 @@
                 const pb::Attribute& pbAttr = pbCompoundValue.attr();
                 std::unique_ptr<Attribute> attr = util::make_unique<Attribute>(isWeak);
                 attr->typeMask = pbAttr.format_flags();
+                attr->minInt = pbAttr.min_int();
+                attr->maxInt = pbAttr.max_int();
                 for (const pb::Attribute_Symbol& pbSymbol : pbAttr.symbols()) {
                     Attribute::Symbol symbol;
                     deserializeItemCommon(pbSymbol, &symbol.symbol);