Merge "Return actual userId when File Based Encryption is present"
diff --git a/Android.mk b/Android.mk
index 9029f4e..f0c0117 100644
--- a/Android.mk
+++ b/Android.mk
@@ -68,6 +68,8 @@
 	core/java/android/app/IActivityContainerCallback.aidl \
 	core/java/android/app/IActivityController.aidl \
 	core/java/android/app/IActivityPendingResult.aidl \
+	core/java/android/app/IAlarmCompleteListener.aidl \
+	core/java/android/app/IAlarmListener.aidl \
 	core/java/android/app/IAlarmManager.aidl \
 	core/java/android/app/IAppTask.aidl \
 	core/java/android/app/ITaskStackListener.aidl \
@@ -686,7 +688,7 @@
 # Common sources for doc check and api check
 common_src_files := \
 	$(call find-other-html-files, $(html_dirs)) \
-	$(addprefix ../../libcore/, $(libcore_to_document)) \
+	$(addprefix ../../, $(libcore_to_document)) \
 	$(addprefix ../../external/junit/, $(junit_to_document))
 
 # These are relative to frameworks/base
diff --git a/api/current.txt b/api/current.txt
index d70317e..3b4e3a9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -321,7 +321,7 @@
     field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
     field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
     field public static final int buttonBarStyle = 16843566; // 0x101032e
-    field public static final int buttonGravity = 16844030; // 0x10104fe
+    field public static final int buttonGravity = 16844031; // 0x10104ff
     field public static final int buttonStyle = 16842824; // 0x1010048
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -371,7 +371,7 @@
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int collapseContentDescription = 16843984; // 0x10104d0
-    field public static final int collapseIcon = 16844031; // 0x10104ff
+    field public static final int collapseIcon = 16844032; // 0x1010500
     field public static final int color = 16843173; // 0x10101a5
     field public static final int colorAccent = 16843829; // 0x1010435
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -412,7 +412,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
-    field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+    field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -780,7 +780,7 @@
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
     field public static final int letterSpacing = 16843958; // 0x10104b6
-    field public static final int level = 16844032; // 0x1010500
+    field public static final int level = 16844033; // 0x1010501
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -813,7 +813,7 @@
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int matchOrder = 16843855; // 0x101044f
     field public static final int max = 16843062; // 0x1010136
-    field public static final int maxButtonHeight = 16844029; // 0x10104fd
+    field public static final int maxButtonHeight = 16844030; // 0x10104fe
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
     field public static final int maxHeight = 16843040; // 0x1010120
@@ -1174,6 +1174,7 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
+    field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1222,7 +1223,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
-    field public static final int textAppearancePopupMenuHeader = 16844034; // 0x1010502
+    field public static final int textAppearancePopupMenuHeader = 16844035; // 0x1010503
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1291,11 +1292,11 @@
     field public static final int tintMode = 16843771; // 0x10103fb
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleMargin = 16844024; // 0x10104f8
-    field public static final int titleMarginBottom = 16844028; // 0x10104fc
-    field public static final int titleMarginEnd = 16844026; // 0x10104fa
-    field public static final int titleMarginStart = 16844025; // 0x10104f9
-    field public static final int titleMarginTop = 16844027; // 0x10104fb
+    field public static final int titleMargin = 16844025; // 0x10104f9
+    field public static final int titleMarginBottom = 16844029; // 0x10104fd
+    field public static final int titleMarginEnd = 16844027; // 0x10104fb
+    field public static final int titleMarginStart = 16844026; // 0x10104fa
+    field public static final int titleMarginTop = 16844028; // 0x10104fc
     field public static final int titleTextAppearance = 16843822; // 0x101042e
     field public static final int titleTextColor = 16844003; // 0x10104e3
     field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1395,6 +1396,7 @@
     field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
+    field public static final int windowBackgroundFallback = 16844036; // 0x1010504
     field public static final int windowClipToOutline = 16843947; // 0x10104ab
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -1420,7 +1422,6 @@
     field public static final int windowNoTitle = 16842838; // 0x1010056
     field public static final int windowOverscan = 16843727; // 0x10103cf
     field public static final int windowReenterTransition = 16843951; // 0x10104af
-    field public static final int windowResizingBackground = 16844035; // 0x1010503
     field public static final int windowReturnTransition = 16843950; // 0x10104ae
     field public static final int windowSharedElementEnterTransition = 16843833; // 0x1010439
     field public static final int windowSharedElementExitTransition = 16843834; // 0x101043a
@@ -3763,17 +3764,21 @@
 
   public class AlarmManager {
     method public void cancel(android.app.PendingIntent);
+    method public void cancel(android.app.AlarmManager.OnAlarmListener);
     method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
     method public void set(int, long, android.app.PendingIntent);
+    method public void set(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
     method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setExact(int, long, android.app.PendingIntent);
+    method public void setExact(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
     method public void setRepeating(int, long, long, android.app.PendingIntent);
     method public void setTime(long);
     method public void setTimeZone(java.lang.String);
     method public void setWindow(int, long, long, android.app.PendingIntent);
+    method public void setWindow(int, long, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     field public static final java.lang.String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
@@ -3795,6 +3800,10 @@
     field public static final android.os.Parcelable.Creator<android.app.AlarmManager.AlarmClockInfo> CREATOR;
   }
 
+  public static abstract interface AlarmManager.OnAlarmListener {
+    method public abstract void onAlarm();
+  }
+
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
@@ -4829,17 +4838,17 @@
     field public android.app.Notification.Action[] actions;
     field public android.media.AudioAttributes audioAttributes;
     field public deprecated int audioStreamType;
-    field public android.widget.RemoteViews bigContentView;
+    field public deprecated android.widget.RemoteViews bigContentView;
     field public java.lang.String category;
     field public int color;
     field public android.app.PendingIntent contentIntent;
-    field public android.widget.RemoteViews contentView;
+    field public deprecated android.widget.RemoteViews contentView;
     field public int defaults;
     field public android.app.PendingIntent deleteIntent;
     field public android.os.Bundle extras;
     field public int flags;
     field public android.app.PendingIntent fullScreenIntent;
-    field public android.widget.RemoteViews headsUpContentView;
+    field public deprecated android.widget.RemoteViews headsUpContentView;
     field public deprecated int icon;
     field public int iconLevel;
     field public deprecated android.graphics.Bitmap largeIcon;
@@ -4930,14 +4939,22 @@
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
+    method public android.widget.RemoteViews makeBigContentView();
+    method public android.widget.RemoteViews makeContentView();
+    method public android.widget.RemoteViews makeHeadsUpContentView();
+    method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
+    method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
     method public android.app.Notification.Builder setColor(int);
-    method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
+    method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
+    method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
+    method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
     method public android.app.Notification.Builder setDefaults(int);
     method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setExtras(android.os.Bundle);
@@ -5872,6 +5889,7 @@
     method public java.lang.String getStructuredData();
     method public android.net.Uri getWebUri();
     method public boolean isAppProvidedIntent();
+    method public boolean isAppProvidedWebUri();
     method public void setClipData(android.content.ClipData);
     method public void setIntent(android.content.Intent);
     method public void setStructuredData(java.lang.String);
@@ -9408,6 +9426,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
+    field public static final java.lang.String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
     field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad";
     field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
@@ -22152,6 +22171,7 @@
     field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259
     field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5
     field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305
+    field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff
     field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff
     field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb
     field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe
@@ -22175,6 +22195,7 @@
     field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef
     field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f
     field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43
+    field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2
     field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2
     field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400
     field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314
@@ -22264,6 +22285,7 @@
     field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51
     field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52
     field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50
+    field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20
     field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000
     field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6
     field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2
@@ -22309,6 +22331,7 @@
     field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064
     field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066
     field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1
     field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4
     field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5
     field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f
@@ -25035,6 +25058,7 @@
     field public static final int OUTGOING_TYPE = 2; // 0x2
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final java.lang.String POST_DIAL_DIGITS = "post_dial_digits";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
@@ -36462,6 +36486,7 @@
     method public boolean performHapticFeedback(int);
     method public boolean performHapticFeedback(int, int);
     method public boolean performLongClick();
+    method public boolean performLongClick(float, float);
     method public void playSoundEffect(int);
     method public boolean post(java.lang.Runnable);
     method public boolean postDelayed(java.lang.Runnable, long);
@@ -37439,6 +37464,8 @@
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setDecorView(android.view.View);
+    method public abstract void setDecorView(int);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
     method public void setElevation(float);
@@ -39197,6 +39224,7 @@
     method public abstract android.net.Uri getUrl();
     method public abstract boolean hasGesture();
     method public abstract boolean isForMainFrame();
+    method public abstract boolean isRedirect();
   }
 
   public class WebResourceResponse {
@@ -39559,7 +39587,8 @@
     method public deprecated android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
     method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, android.webkit.WebResourceRequest);
     method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
-    method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+    method public deprecated boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+    method public boolean shouldOverrideUrlLoading(android.webkit.WebView, android.webkit.WebResourceRequest);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
diff --git a/api/system-current.txt b/api/system-current.txt
index f44065e..9db70e3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -413,7 +413,7 @@
     field public static final int buttonBarNeutralButtonStyle = 16843914; // 0x101048a
     field public static final int buttonBarPositiveButtonStyle = 16843913; // 0x1010489
     field public static final int buttonBarStyle = 16843566; // 0x101032e
-    field public static final int buttonGravity = 16844030; // 0x10104fe
+    field public static final int buttonGravity = 16844031; // 0x10104ff
     field public static final int buttonStyle = 16842824; // 0x1010048
     field public static final int buttonStyleInset = 16842826; // 0x101004a
     field public static final int buttonStyleSmall = 16842825; // 0x1010049
@@ -463,7 +463,7 @@
     field public static final int codes = 16843330; // 0x1010242
     field public static final int collapseColumns = 16843083; // 0x101014b
     field public static final int collapseContentDescription = 16843984; // 0x10104d0
-    field public static final int collapseIcon = 16844031; // 0x10104ff
+    field public static final int collapseIcon = 16844032; // 0x1010500
     field public static final int color = 16843173; // 0x10101a5
     field public static final int colorAccent = 16843829; // 0x1010435
     field public static final int colorActivatedHighlight = 16843664; // 0x1010390
@@ -504,7 +504,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
-    field public static final int contextPopupMenuStyle = 16844033; // 0x1010501
+    field public static final int contextPopupMenuStyle = 16844034; // 0x1010502
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -872,7 +872,7 @@
     field public static final int layout_y = 16843136; // 0x1010180
     field public static final int left = 16843181; // 0x10101ad
     field public static final int letterSpacing = 16843958; // 0x10104b6
-    field public static final int level = 16844032; // 0x1010500
+    field public static final int level = 16844033; // 0x1010501
     field public static final int lineSpacingExtra = 16843287; // 0x1010217
     field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
     field public static final int lines = 16843092; // 0x1010154
@@ -905,7 +905,7 @@
     field public static final int marqueeRepeatLimit = 16843293; // 0x101021d
     field public static final int matchOrder = 16843855; // 0x101044f
     field public static final int max = 16843062; // 0x1010136
-    field public static final int maxButtonHeight = 16844029; // 0x10104fd
+    field public static final int maxButtonHeight = 16844030; // 0x10104fe
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
     field public static final int maxHeight = 16843040; // 0x1010120
@@ -1270,6 +1270,7 @@
     field public static final int summaryOn = 16843247; // 0x10101ef
     field public static final int supportsAssist = 16844016; // 0x10104f0
     field public static final int supportsLaunchVoiceAssistFromKeyguard = 16844017; // 0x10104f1
+    field public static final int supportsPictureInPicture = 16844024; // 0x10104f8
     field public static final int supportsRtl = 16843695; // 0x10103af
     field public static final int supportsSwitchingToNextInputMethod = 16843755; // 0x10103eb
     field public static final int supportsUploading = 16843419; // 0x101029b
@@ -1318,7 +1319,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
-    field public static final int textAppearancePopupMenuHeader = 16844034; // 0x1010502
+    field public static final int textAppearancePopupMenuHeader = 16844035; // 0x1010503
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -1387,11 +1388,11 @@
     field public static final int tintMode = 16843771; // 0x10103fb
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
-    field public static final int titleMargin = 16844024; // 0x10104f8
-    field public static final int titleMarginBottom = 16844028; // 0x10104fc
-    field public static final int titleMarginEnd = 16844026; // 0x10104fa
-    field public static final int titleMarginStart = 16844025; // 0x10104f9
-    field public static final int titleMarginTop = 16844027; // 0x10104fb
+    field public static final int titleMargin = 16844025; // 0x10104f9
+    field public static final int titleMarginBottom = 16844029; // 0x10104fd
+    field public static final int titleMarginEnd = 16844027; // 0x10104fb
+    field public static final int titleMarginStart = 16844026; // 0x10104fa
+    field public static final int titleMarginTop = 16844028; // 0x10104fc
     field public static final int titleTextAppearance = 16843822; // 0x101042e
     field public static final int titleTextColor = 16844003; // 0x10104e3
     field public static final int titleTextStyle = 16843512; // 0x10102f8
@@ -1491,6 +1492,7 @@
     field public static final int windowAllowReturnTransitionOverlap = 16843835; // 0x101043b
     field public static final int windowAnimationStyle = 16842926; // 0x10100ae
     field public static final int windowBackground = 16842836; // 0x1010054
+    field public static final int windowBackgroundFallback = 16844036; // 0x1010504
     field public static final int windowClipToOutline = 16843947; // 0x10104ab
     field public static final int windowCloseOnTouchOutside = 16843611; // 0x101035b
     field public static final int windowContentOverlay = 16842841; // 0x1010059
@@ -1516,7 +1518,6 @@
     field public static final int windowNoTitle = 16842838; // 0x1010056
     field public static final int windowOverscan = 16843727; // 0x10103cf
     field public static final int windowReenterTransition = 16843951; // 0x10104af
-    field public static final int windowResizingBackground = 16844035; // 0x1010503
     field public static final int windowReturnTransition = 16843950; // 0x10104ae
     field public static final int windowSharedElementEnterTransition = 16843833; // 0x1010439
     field public static final int windowSharedElementExitTransition = 16843834; // 0x101043a
@@ -3872,18 +3873,22 @@
 
   public class AlarmManager {
     method public void cancel(android.app.PendingIntent);
+    method public void cancel(android.app.AlarmManager.OnAlarmListener);
     method public android.app.AlarmManager.AlarmClockInfo getNextAlarmClock();
     method public void set(int, long, android.app.PendingIntent);
+    method public void set(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void set(int, long, long, long, android.app.PendingIntent, android.os.WorkSource);
     method public void setAlarmClock(android.app.AlarmManager.AlarmClockInfo, android.app.PendingIntent);
     method public void setAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setExact(int, long, android.app.PendingIntent);
+    method public void setExact(int, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     method public void setExactAndAllowWhileIdle(int, long, android.app.PendingIntent);
     method public void setInexactRepeating(int, long, long, android.app.PendingIntent);
     method public void setRepeating(int, long, long, android.app.PendingIntent);
     method public void setTime(long);
     method public void setTimeZone(java.lang.String);
     method public void setWindow(int, long, long, android.app.PendingIntent);
+    method public void setWindow(int, long, long, java.lang.String, android.app.AlarmManager.OnAlarmListener, android.os.Handler);
     field public static final java.lang.String ACTION_NEXT_ALARM_CLOCK_CHANGED = "android.app.action.NEXT_ALARM_CLOCK_CHANGED";
     field public static final int ELAPSED_REALTIME = 3; // 0x3
     field public static final int ELAPSED_REALTIME_WAKEUP = 2; // 0x2
@@ -3905,6 +3910,10 @@
     field public static final android.os.Parcelable.Creator<android.app.AlarmManager.AlarmClockInfo> CREATOR;
   }
 
+  public static abstract interface AlarmManager.OnAlarmListener {
+    method public abstract void onAlarm();
+  }
+
   public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface {
     ctor protected AlertDialog(android.content.Context);
     ctor protected AlertDialog(android.content.Context, boolean, android.content.DialogInterface.OnCancelListener);
@@ -4946,17 +4955,17 @@
     field public android.app.Notification.Action[] actions;
     field public android.media.AudioAttributes audioAttributes;
     field public deprecated int audioStreamType;
-    field public android.widget.RemoteViews bigContentView;
+    field public deprecated android.widget.RemoteViews bigContentView;
     field public java.lang.String category;
     field public int color;
     field public android.app.PendingIntent contentIntent;
-    field public android.widget.RemoteViews contentView;
+    field public deprecated android.widget.RemoteViews contentView;
     field public int defaults;
     field public android.app.PendingIntent deleteIntent;
     field public android.os.Bundle extras;
     field public int flags;
     field public android.app.PendingIntent fullScreenIntent;
-    field public android.widget.RemoteViews headsUpContentView;
+    field public deprecated android.widget.RemoteViews headsUpContentView;
     field public deprecated int icon;
     field public int iconLevel;
     field public deprecated android.graphics.Bitmap largeIcon;
@@ -5047,14 +5056,22 @@
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
     method public deprecated android.app.Notification getNotification();
+    method public android.widget.RemoteViews makeBigContentView();
+    method public android.widget.RemoteViews makeContentView();
+    method public android.widget.RemoteViews makeHeadsUpContentView();
+    method public static android.app.Notification.Builder recoverBuilder(android.content.Context, android.app.Notification);
+    method public android.app.Notification.Builder setActions(android.app.Notification.Action...);
     method public android.app.Notification.Builder setAutoCancel(boolean);
     method public android.app.Notification.Builder setCategory(java.lang.String);
     method public android.app.Notification.Builder setColor(int);
-    method public android.app.Notification.Builder setContent(android.widget.RemoteViews);
+    method public deprecated android.app.Notification.Builder setContent(android.widget.RemoteViews);
     method public android.app.Notification.Builder setContentInfo(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setContentText(java.lang.CharSequence);
     method public android.app.Notification.Builder setContentTitle(java.lang.CharSequence);
+    method public android.app.Notification.Builder setCustomBigContentView(android.widget.RemoteViews);
+    method public android.app.Notification.Builder setCustomContentView(android.widget.RemoteViews);
+    method public android.app.Notification.Builder setCustomHeadsUpContentView(android.widget.RemoteViews);
     method public android.app.Notification.Builder setDefaults(int);
     method public android.app.Notification.Builder setDeleteIntent(android.app.PendingIntent);
     method public android.app.Notification.Builder setExtras(android.os.Bundle);
@@ -6005,6 +6022,7 @@
     method public java.lang.String getStructuredData();
     method public android.net.Uri getWebUri();
     method public boolean isAppProvidedIntent();
+    method public boolean isAppProvidedWebUri();
     method public void setClipData(android.content.ClipData);
     method public void setIntent(android.content.Intent);
     method public void setStructuredData(java.lang.String);
@@ -9702,6 +9720,7 @@
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
     field public static final java.lang.String FEATURE_FINGERPRINT = "android.hardware.fingerprint";
+    field public static final java.lang.String FEATURE_FREEFORM_WINDOW_MANAGEMENT = "android.software.freeform_window_management";
     field public static final java.lang.String FEATURE_GAMEPAD = "android.hardware.gamepad";
     field public static final java.lang.String FEATURE_HIFI_SENSORS = "android.hardware.sensor.hifi_sensors";
     field public static final java.lang.String FEATURE_HOME_SCREEN = "android.software.home_screen";
@@ -20804,7 +20823,7 @@
 
 package android.net.wifi {
 
-  public class BatchedScanResult implements android.os.Parcelable {
+  public deprecated class BatchedScanResult implements android.os.Parcelable {
     ctor public BatchedScanResult();
     ctor public BatchedScanResult(android.net.wifi.BatchedScanResult);
     method public int describeContents();
@@ -21215,7 +21234,7 @@
     method public boolean disableNetwork(int);
     method public boolean disconnect();
     method public boolean enableNetwork(int, boolean);
-    method public java.util.List<android.net.wifi.BatchedScanResult> getBatchedScanResults();
+    method public deprecated java.util.List<android.net.wifi.BatchedScanResult> getBatchedScanResults();
     method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
@@ -21225,7 +21244,7 @@
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
-    method public boolean isBatchedScanSupported();
+    method public deprecated boolean isBatchedScanSupported();
     method public boolean isDeviceToApRttSupported();
     method public boolean isDeviceToDeviceRttSupported();
     method public boolean isEnhancedPowerReportingSupported();
@@ -21245,7 +21264,7 @@
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
-    method public boolean startLocationRestrictedScan(android.os.WorkSource);
+    method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
     method public boolean startScan();
     method public boolean startScan(android.os.WorkSource);
     method public void startWps(android.net.wifi.WpsInfo, android.net.wifi.WifiManager.WpsCallback);
@@ -24097,6 +24116,7 @@
     field public static final int GL_ACTIVE_PROGRAM = 33369; // 0x8259
     field public static final int GL_ACTIVE_RESOURCES = 37621; // 0x92f5
     field public static final int GL_ACTIVE_VARIABLES = 37637; // 0x9305
+    field public static final int GL_ALL_BARRIER_BITS = -1; // 0xffffffff
     field public static final int GL_ALL_SHADER_BITS = -1; // 0xffffffff
     field public static final int GL_ARRAY_SIZE = 37627; // 0x92fb
     field public static final int GL_ARRAY_STRIDE = 37630; // 0x92fe
@@ -24120,6 +24140,7 @@
     field public static final int GL_DISPATCH_INDIRECT_BUFFER_BINDING = 37103; // 0x90ef
     field public static final int GL_DRAW_INDIRECT_BUFFER = 36671; // 0x8f3f
     field public static final int GL_DRAW_INDIRECT_BUFFER_BINDING = 36675; // 0x8f43
+    field public static final int GL_ELEMENT_ARRAY_BARRIER_BIT = 2; // 0x2
     field public static final int GL_FRAGMENT_SHADER_BIT = 2; // 0x2
     field public static final int GL_FRAMEBUFFER_BARRIER_BIT = 1024; // 0x400
     field public static final int GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS = 37652; // 0x9314
@@ -24209,6 +24230,7 @@
     field public static final int GL_SAMPLE_MASK = 36433; // 0x8e51
     field public static final int GL_SAMPLE_MASK_VALUE = 36434; // 0x8e52
     field public static final int GL_SAMPLE_POSITION = 36432; // 0x8e50
+    field public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT = 32; // 0x20
     field public static final int GL_SHADER_STORAGE_BARRIER_BIT = 8192; // 0x2000
     field public static final int GL_SHADER_STORAGE_BLOCK = 37606; // 0x92e6
     field public static final int GL_SHADER_STORAGE_BUFFER = 37074; // 0x90d2
@@ -24254,6 +24276,7 @@
     field public static final int GL_UNSIGNED_INT_IMAGE_3D = 36964; // 0x9064
     field public static final int GL_UNSIGNED_INT_IMAGE_CUBE = 36966; // 0x9066
     field public static final int GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE = 37130; // 0x910a
+    field public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 1; // 0x1
     field public static final int GL_VERTEX_ATTRIB_BINDING = 33492; // 0x82d4
     field public static final int GL_VERTEX_ATTRIB_RELATIVE_OFFSET = 33493; // 0x82d5
     field public static final int GL_VERTEX_BINDING_BUFFER = 36687; // 0x8f4f
@@ -26993,6 +27016,7 @@
     field public static final int OUTGOING_TYPE = 2; // 0x2
     field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
     field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
+    field public static final java.lang.String POST_DIAL_DIGITS = "post_dial_digits";
     field public static final int PRESENTATION_ALLOWED = 1; // 0x1
     field public static final int PRESENTATION_PAYPHONE = 4; // 0x4
     field public static final int PRESENTATION_RESTRICTED = 2; // 0x2
@@ -38759,6 +38783,7 @@
     method public boolean performHapticFeedback(int);
     method public boolean performHapticFeedback(int, int);
     method public boolean performLongClick();
+    method public boolean performLongClick(float, float);
     method public void playSoundEffect(int);
     method public boolean post(java.lang.Runnable);
     method public boolean postDelayed(java.lang.Runnable, long);
@@ -39736,6 +39761,8 @@
     method public abstract void setContentView(int);
     method public abstract void setContentView(android.view.View);
     method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
+    method public abstract void setDecorView(android.view.View);
+    method public abstract void setDecorView(int);
     method protected void setDefaultWindowFormat(int);
     method public void setDimAmount(float);
     method public void setDisableWallpaperTouchEvents(boolean);
@@ -41557,6 +41584,7 @@
     method public abstract android.net.Uri getUrl();
     method public abstract boolean hasGesture();
     method public abstract boolean isForMainFrame();
+    method public abstract boolean isRedirect();
   }
 
   public class WebResourceResponse {
@@ -41966,7 +41994,8 @@
     method public deprecated android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, java.lang.String);
     method public android.webkit.WebResourceResponse shouldInterceptRequest(android.webkit.WebView, android.webkit.WebResourceRequest);
     method public boolean shouldOverrideKeyEvent(android.webkit.WebView, android.view.KeyEvent);
-    method public boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+    method public deprecated boolean shouldOverrideUrlLoading(android.webkit.WebView, java.lang.String);
+    method public boolean shouldOverrideUrlLoading(android.webkit.WebView, android.webkit.WebResourceRequest);
     field public static final int ERROR_AUTHENTICATION = -4; // 0xfffffffc
     field public static final int ERROR_BAD_URL = -12; // 0xfffffff4
     field public static final int ERROR_CONNECT = -6; // 0xfffffffa
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 1e2e33d..12780a8 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -154,7 +154,7 @@
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
-                "       am stack split <STACK_ID> <v|h> [INTENT]\n" +
+                "       am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
                 "       am stack list\n" +
                 "       am stack info <STACK_ID>\n" +
@@ -297,11 +297,9 @@
                 "   <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
                 "   applying the optional [DELAY_MS] between each step.\n" +
                 "\n" +
-                "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" +
-                "   starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" +
-                "   specified and the current stack has more than one task, then the top task\n" +
-                "   of the current task will be moved to the new stack. Command will also force\n" +
-                "   all current tasks in both stacks to be resizeable.\n" +
+                "am stack move-top-activity-to-pinned-stack: moves the top activity from\n" +
+                "   <STACK_ID> to the pinned stack using <LEFT,TOP,RIGHT,BOTTOM> for the\n" +
+                "   bounds of the pinned stack.\n" +
                 "\n" +
                 "am stack positiontask: place <TASK_ID> in <STACK_ID> at <POSITION>" +
                 "\n" +
@@ -1954,25 +1952,34 @@
 
     private void runStack() throws Exception {
         String op = nextArgRequired();
-        if (op.equals("start")) {
-            runStackStart();
-        } else if (op.equals("movetask")) {
-            runStackMoveTask();
-        } else if (op.equals("resize")) {
-            runStackResize();
-        } else if (op.equals("positiontask")) {
-            runStackPositionTask();
-        } else if (op.equals("list")) {
-            runStackList();
-        } else if (op.equals("info")) {
-            runStackInfo();
-        } else if (op.equals("split")) {
-            runStackSplit();
-        } else if (op.equals("size-docked-stack-test")) {
-            runStackSizeDockedStackTest();
-        } else {
-            showError("Error: unknown command '" + op + "'");
-            return;
+        switch (op) {
+            case "start":
+                runStackStart();
+                break;
+            case "movetask":
+                runStackMoveTask();
+                break;
+            case "resize":
+                runStackResize();
+                break;
+            case "positiontask":
+                runStackPositionTask();
+                break;
+            case "list":
+                runStackList();
+                break;
+            case "info":
+                runStackInfo();
+                break;
+            case "move-top-activity-to-pinned-stack":
+                runMoveTopActivityToPinnedStack();
+                break;
+            case "size-docked-stack-test":
+                runStackSizeDockedStackTest();
+                break;
+            default:
+                showError("Error: unknown command '" + op + "'");
+                break;
         }
     }
 
@@ -2072,61 +2079,21 @@
         }
     }
 
-    private void runStackSplit() throws Exception {
-        final int stackId = Integer.valueOf(nextArgRequired());
-        final String splitDirection = nextArgRequired();
-        Intent intent = null;
-        try {
-            intent = makeIntent(UserHandle.USER_CURRENT);
-        } catch (IllegalArgumentException e) {
-            // no intent supplied.
+    private void runMoveTopActivityToPinnedStack() throws Exception {
+        int stackId = Integer.valueOf(nextArgRequired());
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
         }
 
         try {
-            final StackInfo currentStackInfo = mAm.getStackInfo(stackId);
-            // Calculate bounds for new and current stack.
-            final Rect currentStackBounds = new Rect(currentStackInfo.bounds);
-            final Rect newStackBounds = new Rect(currentStackInfo.bounds);
-            if ("v".equals(splitDirection)) {
-                currentStackBounds.right = newStackBounds.left = currentStackInfo.bounds.centerX();
-            } else if ("h".equals(splitDirection)) {
-                currentStackBounds.bottom = newStackBounds.top = currentStackInfo.bounds.centerY();
-            } else {
-                showError("Error: unknown split direction '" + splitDirection + "'");
-                return;
+            if (!mAm.moveTopActivityToPinnedStack(stackId, bounds)) {
+                showError("Didn't move top activity to pinned stack.");
             }
-
-            // Create new stack
-            IActivityContainer container = mAm.createStackOnDisplay(currentStackInfo.displayId);
-            if (container == null) {
-                showError("Error: Unable to create new stack...");
-            }
-
-            final int newStackId = container.getStackId();
-
-            if (intent != null) {
-                container.startActivity(intent);
-            } else if (currentStackInfo.taskIds != null && currentStackInfo.taskIds.length > 1) {
-                // Move top task over to new stack
-                mAm.moveTaskToStack(currentStackInfo.taskIds[currentStackInfo.taskIds.length - 1],
-                        newStackId, true);
-            }
-
-            final StackInfo newStackInfo = mAm.getStackInfo(newStackId);
-
-            // Make all tasks in the stacks resizeable.
-            for (int taskId : currentStackInfo.taskIds) {
-                mAm.setTaskResizeable(taskId, true);
-            }
-
-            for (int taskId : newStackInfo.taskIds) {
-                mAm.setTaskResizeable(taskId, true);
-            }
-
-            // Resize stacks
-            mAm.resizeStack(currentStackInfo.stackId, currentStackBounds, false);
-            mAm.resizeStack(newStackInfo.stackId, newStackBounds, false);
         } catch (RemoteException e) {
+            showError("Unable to move top activity: " + e);
+            return;
         }
     }
 
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3f8e311..2960cdc 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -283,7 +283,7 @@
             } else if (args.length == 2) {
                 if (args[0].equalsIgnoreCase("-p")) {
                     validCommand = true;
-                    return displayPackageFilePath(args[1], UserHandle.USER_OWNER);
+                    return displayPackageFilePath(args[1], UserHandle.USER_SYSTEM);
                 }
             }
             return 1;
@@ -767,7 +767,7 @@
     }
 
     private int runPath() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1650,7 +1650,7 @@
     }
 
     private int runClear() {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1722,7 +1722,7 @@
     }
 
     private int runSetEnabledSetting(int state) {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
@@ -1771,7 +1771,7 @@
     }
 
     private int runSetHiddenSetting(boolean state) {
-        int userId = UserHandle.USER_OWNER;
+        int userId = UserHandle.USER_SYSTEM;
         String option = nextOption();
         if (option != null && option.equals("--user")) {
             String optionData = nextOptionData();
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3bfeff0..fce1b2e 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -434,10 +434,17 @@
     public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
 
     /**
+     * ID of stack that always on top (always visible) when it exist.
+     * Mainly used for this in Picture-in-Picture mode.
+     * @hide
+     */
+    public static final int PINNED_STACK_ID = DOCKED_STACK_ID + 1;
+
+    /**
      * Last static stack stack ID.
      * @hide
      */
-    public static final int LAST_STATIC_STACK_ID = DOCKED_STACK_ID;
+    public static final int LAST_STATIC_STACK_ID = PINNED_STACK_ID;
 
     /**
      * Start of ID range used by stacks that are created dynamically.
@@ -1193,6 +1200,12 @@
         public int id;
 
         /**
+         * The stack that currently contains this task.
+         * @hide
+         */
+        public int stackId;
+
+        /**
          * The component launched as the first activity in the task.  This can
          * be considered the "application" of this task.
          */
@@ -1241,6 +1254,7 @@
 
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeInt(id);
+            dest.writeInt(stackId);
             ComponentName.writeToParcel(baseActivity, dest);
             ComponentName.writeToParcel(topActivity, dest);
             if (thumbnail != null) {
@@ -1257,6 +1271,7 @@
 
         public void readFromParcel(Parcel source) {
             id = source.readInt();
+            stackId = source.readInt();
             baseActivity = ComponentName.readFromParcel(source);
             topActivity = ComponentName.readFromParcel(source);
             if (source.readInt() != 0) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b97f947..da743f8 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -116,21 +116,22 @@
     static public void noteWakeupAlarm(PendingIntent ps, int sourceUid, String sourcePkg,
             String tag) {
         try {
-            getDefault().noteWakeupAlarm(ps.getTarget(), sourceUid, sourcePkg, tag);
+            getDefault().noteWakeupAlarm((ps != null) ? ps.getTarget() : null,
+                    sourceUid, sourcePkg, tag);
         } catch (RemoteException ex) {
         }
     }
 
     static public void noteAlarmStart(PendingIntent ps, int sourceUid, String tag) {
         try {
-            getDefault().noteAlarmStart(ps.getTarget(), sourceUid, tag);
+            getDefault().noteAlarmStart((ps != null) ? ps.getTarget() : null, sourceUid, tag);
         } catch (RemoteException ex) {
         }
     }
 
     static public void noteAlarmFinish(PendingIntent ps, int sourceUid, String tag) {
         try {
-            getDefault().noteAlarmFinish(ps.getTarget(), sourceUid, tag);
+            getDefault().noteAlarmFinish((ps != null) ? ps.getTarget() : null, sourceUid, tag);
         } catch (RemoteException ex) {
         }
     }
@@ -755,6 +756,16 @@
             return true;
         }
 
+        case MOVE_TOP_ACTIVITY_TO_PINNED_STACK: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final int stackId = data.readInt();
+            final Rect r = Rect.CREATOR.createFromParcel(data);
+            final boolean res = moveTopActivityToPinnedStack(stackId, r);
+            reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
+            return true;
+        }
+
         case RESIZE_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final int stackId = data.readInt();
@@ -2670,19 +2681,10 @@
         case REPORT_SIZE_CONFIGURATIONS: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
-            int horizontalSize = data.readInt();
-            int[] horizontal = null;
-            if (horizontalSize > 0) {
-                horizontal = new int[horizontalSize];
-                data.readIntArray(horizontal);
-            }
-            int[] vertical = null;
-            int verticalSize = data.readInt();
-            if (verticalSize > 0) {
-                vertical = new int[verticalSize];
-                data.readIntArray(vertical);
-            }
-            reportSizeConfigurations(token, horizontal, vertical);
+            int[] horizontal = readIntArray(data);
+            int[] vertical = readIntArray(data);
+            int[] smallest = readIntArray(data);
+            reportSizeConfigurations(token, horizontal, vertical, smallest);
             return true;
         }
         case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
@@ -2704,6 +2706,16 @@
         return super.onTransact(code, data, reply, flags);
     }
 
+    private int[] readIntArray(Parcel data) {
+        int[] smallest = null;
+        int smallestSize = data.readInt();
+        if (smallestSize > 0) {
+            smallest = new int[smallestSize];
+            data.readIntArray(smallest);
+        }
+        return smallest;
+    }
+
     public IBinder asBinder() {
         return this;
     }
@@ -3555,6 +3567,22 @@
         reply.recycle();
     }
     @Override
+    public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
+        throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(stackId);
+        r.writeToParcel(data, 0);
+        mRemote.transact(MOVE_TOP_ACTIVITY_TO_PINNED_STACK, data, reply, 0);
+        reply.readException();
+        final boolean res = reply.readInt() != 0;
+        data.recycle();
+        reply.recycle();
+        return res;
+    }
+    @Override
     public void resizeStack(int stackId, Rect r, boolean allowResizeInDockedMode)
             throws RemoteException
     {
@@ -6214,29 +6242,30 @@
 
     @Override
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations) throws RemoteException {
+            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(token);
-        if (horizontalSizeConfiguration == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(horizontalSizeConfiguration.length);
-            data.writeIntArray(horizontalSizeConfiguration);
-        }
-        if (verticalSizeConfigurations == null) {
-            data.writeInt(0);
-        } else {
-            data.writeInt(verticalSizeConfigurations.length);
-            data.writeIntArray(verticalSizeConfigurations);
-        }
+        writeIntArray(horizontalSizeConfiguration, data);
+        writeIntArray(verticalSizeConfigurations, data);
+        writeIntArray(smallestSizeConfigurations, data);
         mRemote.transact(REPORT_SIZE_CONFIGURATIONS, data, reply, 0);
         reply.readException();
         data.recycle();
         reply.recycle();
     }
 
+    private static void writeIntArray(int[] array, Parcel data) {
+        if (array == null) {
+            data.writeInt(0);
+        } else {
+            data.writeInt(array.length);
+            data.writeIntArray(array);
+        }
+    }
+
     @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 933f98d..6107dfd 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
@@ -23,10 +25,12 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.util.Pair;
 import android.util.Slog;
+import android.view.AppTransitionAnimationSpec;
 import android.view.View;
 import android.view.Window;
 
@@ -127,6 +131,24 @@
     public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener";
 
     /**
+     * Callback for when the last frame of the animation is played.
+     * @hide
+     */
+    private static final String KEY_ANIMATION_FINISHED_LISTENER =
+            "android:activity.animationFinishedListener";
+
+    /**
+     * Descriptions of app transition animations to be played during the activity launch.
+     */
+    private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
+
+    /**
+     * Where the docked stack should be positioned.
+     * @hide
+     */
+    private static final String KEY_DOCK_CREATE_MODE = "android:activity.dockCreateMode";
+
+    /**
      * For Activity transitions, the calling Activity's TransitionListener used to
      * notify the called Activity when the shared element and the exit transitions
      * complete.
@@ -183,6 +205,7 @@
     private int mWidth;
     private int mHeight;
     private IRemoteCallback mAnimationStartedListener;
+    private IRemoteCallback mAnimationFinishedListener;
     private ResultReceiver mTransitionReceiver;
     private boolean mIsReturning;
     private ArrayList<String> mSharedElementNames;
@@ -190,6 +213,8 @@
     private int mResultCode;
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
+    private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+    private AppTransitionAnimationSpec mAnimSpecs[];
 
     /**
      * Create an ActivityOptions specifying a custom animation to run when
@@ -263,16 +288,15 @@
         return opts;
     }
 
-    private void setOnAnimationStartedListener(Handler handler,
-            OnAnimationStartedListener listener) {
+    private void setOnAnimationStartedListener(final Handler handler,
+            final OnAnimationStartedListener listener) {
         if (listener != null) {
-            final Handler h = handler;
-            final OnAnimationStartedListener finalListener = listener;
             mAnimationStartedListener = new IRemoteCallback.Stub() {
-                @Override public void sendResult(Bundle data) throws RemoteException {
-                    h.post(new Runnable() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    handler.post(new Runnable() {
                         @Override public void run() {
-                            finalListener.onAnimationStarted();
+                            listener.onAnimationStarted();
                         }
                     });
                 }
@@ -289,6 +313,32 @@
         void onAnimationStarted();
     }
 
+    private void setOnAnimationFinishedListener(final Handler handler,
+            final OnAnimationFinishedListener listener) {
+        if (listener != null) {
+            mAnimationFinishedListener = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            listener.onAnimationFinished();
+                        }
+                    });
+                }
+            };
+        }
+    }
+
+    /**
+     * Callback for use with {@link ActivityOptions#makeThumbnailAspectScaleDownAnimation}
+     * to find out when the given animation has drawn its last frame.
+     * @hide
+     */
+    public interface OnAnimationFinishedListener {
+        void onAnimationFinished();
+    }
+
     /**
      * Create an ActivityOptions specifying an animation where the new
      * activity is scaled from a small originating area of the screen to
@@ -503,6 +553,20 @@
         return opts;
     }
 
+    /** @hide */
+    public static ActivityOptions makeThumbnailAspectScaleDownAnimation(View source,
+            AppTransitionAnimationSpec[] specs, Handler handler,
+            OnAnimationStartedListener onAnimationStartedListener,
+            OnAnimationFinishedListener onAnimationFinishedListener) {
+        ActivityOptions opts = new ActivityOptions();
+        opts.mPackageName = source.getContext().getPackageName();
+        opts.mAnimationType = ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
+        opts.mAnimSpecs = specs;
+        opts.setOnAnimationStartedListener(handler, onAnimationStartedListener);
+        opts.setOnAnimationFinishedListener(handler, onAnimationFinishedListener);
+        return opts;
+    }
+
     /**
      * Create an ActivityOptions to transition between Activities using cross-Activity scene
      * animations. This method carries the position of one shared element to the started Activity.
@@ -688,6 +752,18 @@
                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
                 break;
         }
+        mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
+        if (opts.containsKey(KEY_ANIM_SPECS)) {
+            Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
+            mAnimSpecs = new AppTransitionAnimationSpec[specs.length];
+            for (int i = specs.length - 1; i >= 0; i--) {
+                mAnimSpecs[i] = (AppTransitionAnimationSpec) specs[i];
+            }
+        }
+        if (opts.containsKey(KEY_ANIMATION_FINISHED_LISTENER)) {
+            mAnimationFinishedListener = IRemoteCallback.Stub.asInterface(
+                    opts.getBinder(KEY_ANIMATION_FINISHED_LISTENER));
+        }
     }
 
     /** @hide */
@@ -763,6 +839,11 @@
     }
 
     /** @hide */
+    public IRemoteCallback getAnimationFinishedListener() {
+        return mAnimationFinishedListener;
+    }
+
+    /** @hide */
     public int getExitCoordinatorKey() { return mExitCoordinatorIndex; }
 
     /** @hide */
@@ -800,12 +881,23 @@
     }
 
     /** @hide */
+    public AppTransitionAnimationSpec[] getAnimSpecs() { return mAnimSpecs; }
+
+    /** @hide */
     public static void abort(Bundle options) {
         if (options != null) {
             (new ActivityOptions(options)).abort();
         }
     }
 
+    /** @hide */
+    public int getDockCreateMode() { return mDockCreateMode; }
+
+    /** @hide */
+    public void setDockCreateMode(int dockCreateMode) {
+        mDockCreateMode = dockCreateMode;
+    }
+
     /**
      * Update the current values in this ActivityOptions from those supplied
      * in <var>otherOptions</var>.  Any values
@@ -880,6 +972,8 @@
                 mExitCoordinatorIndex = otherOptions.mExitCoordinatorIndex;
                 break;
         }
+        mAnimSpecs = otherOptions.mAnimSpecs;
+        mAnimationFinishedListener = otherOptions.mAnimationFinishedListener;
     }
 
     /**
@@ -945,6 +1039,13 @@
                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                 break;
         }
+        b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
+        if (mAnimSpecs != null) {
+            b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
+        }
+        if (mAnimationFinishedListener != null) {
+            b.putBinder(KEY_ANIMATION_FINISHED_LISTENER, mAnimationFinishedListener.asBinder());
+        }
 
         return b;
     }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b9292de..a74f528 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -88,6 +88,7 @@
 import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.util.SuperNotCalledException;
 import android.view.Display;
 import android.view.HardwareRenderer;
@@ -2638,32 +2639,24 @@
         if (configurations == null) {
             return;
         }
-        IntArray horizontal = new IntArray();
-        IntArray vertical = new IntArray();
+        SparseIntArray horizontal = new SparseIntArray();
+        SparseIntArray vertical = new SparseIntArray();
+        SparseIntArray smallest = new SparseIntArray();
         for (int i = configurations.length - 1; i >= 0; i--) {
             Configuration config = configurations[i];
             if (config.screenHeightDp != Configuration.SCREEN_HEIGHT_DP_UNDEFINED) {
-                vertical.add(config.screenHeightDp);
+                vertical.put(config.screenHeightDp, 0);
             }
             if (config.screenWidthDp != Configuration.SCREEN_WIDTH_DP_UNDEFINED) {
-                horizontal.add(config.screenWidthDp);
+                horizontal.put(config.screenWidthDp, 0);
             }
             if (config.smallestScreenWidthDp != Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
-                vertical.add(config.smallestScreenWidthDp);
-                horizontal.add(config.smallestScreenWidthDp);
+                smallest.put(config.smallestScreenWidthDp, 0);
             }
         }
-        int[] horizontalArray = null;
-        if (horizontal.size() > 0) {
-            horizontalArray = horizontal.toArray();
-        }
-        int[] verticalArray = null;
-        if (vertical.size() > 0) {
-            verticalArray = vertical.toArray();
-        }
         try {
-            ActivityManagerNative.getDefault().reportSizeConfigurations(r.token, horizontalArray,
-                    verticalArray);
+            ActivityManagerNative.getDefault().reportSizeConfigurations(r.token,
+                    horizontal.copyKeys(), vertical.copyKeys(), smallest.copyKeys());
         } catch (RemoteException ex) {
         }
 
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index fb03b62..3dc9582 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -21,15 +21,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.Build;
+import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.text.TextUtils;
+import android.util.Log;
+
 import libcore.util.ZoneInfoDB;
 
 import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.util.WeakHashMap;
 
 /**
  * This class provides access to the system alarm services.  These allow you
@@ -72,6 +78,8 @@
  * Context.getSystemService(Context.ALARM_SERVICE)}.
  */
 public class AlarmManager {
+    private static final String TAG = "AlarmManager";
+
     /**
      * Alarm time in {@link System#currentTimeMillis System.currentTimeMillis()}
      * (wall clock time in UTC), which will wake up the device when
@@ -160,9 +168,89 @@
     public static final int FLAG_IDLE_UNTIL = 1<<4;
 
     private final IAlarmManager mService;
+    private final String mPackageName;
     private final boolean mAlwaysExact;
     private final int mTargetSdkVersion;
+    private final Handler mMainThreadHandler;
 
+    /**
+     * Direct-notification alarms: the requester must be running continuously from the
+     * time the alarm is set to the time it is delivered, or delivery will fail.  Only
+     * one-shot alarms can be set using this mechanism, not repeating alarms.
+     */
+    public interface OnAlarmListener {
+        /**
+         * Callback method that is invoked by the system when the alarm time is reached.
+         */
+        public void onAlarm();
+    }
+
+    final class ListenerWrapper extends IAlarmListener.Stub implements Runnable {
+        final OnAlarmListener mListener;
+        Handler mHandler;
+        IAlarmCompleteListener mCompletion;
+
+        public ListenerWrapper(OnAlarmListener listener) {
+            mListener = listener;
+        }
+
+        public void setHandler(Handler h) {
+           mHandler = h;
+        }
+
+        public void cancel() {
+            try {
+                mService.remove(null, this);
+            } catch (RemoteException ex) {
+            }
+
+            synchronized (AlarmManager.class) {
+                if (sWrappers != null) {
+                    sWrappers.remove(mListener);
+                }
+            }
+        }
+
+        @Override
+        public void doAlarm(IAlarmCompleteListener alarmManager) {
+            mCompletion = alarmManager;
+            mHandler.post(this);
+        }
+
+        @Override
+        public void run() {
+            // Remove this listener from the wrapper cache first; the server side
+            // already considers it gone
+            synchronized (AlarmManager.class) {
+                if (sWrappers != null) {
+                    sWrappers.remove(mListener);
+                }
+            }
+
+            // Now deliver it to the app
+            try {
+                mListener.onAlarm();
+            } finally {
+                // No catch -- make sure to report completion to the system process,
+                // but continue to allow the exception to crash the app.
+
+                try {
+                    mCompletion.alarmComplete(this);
+                } catch (Exception e) {
+                    Log.e(TAG, "Unable to report completion to Alarm Manager!", e);
+                }
+            }
+        }
+    }
+
+    // Tracking of the OnAlarmListener -> wrapper mapping, for cancel() support.
+    // Access is synchronized on the AlarmManager class object.
+    //
+    // These are weak references so that we don't leak listener references if, for
+    // example, the pending-alarm messages are posted to a HandlerThread that is
+    // disposed of prior to alarm delivery.  The underlying messages will be GC'd
+    // but this static reference would still persist, orphaned, never deallocated.
+    private static WeakHashMap<OnAlarmListener, WeakReference<ListenerWrapper>> sWrappers;
 
     /**
      * package private on purpose
@@ -170,8 +258,10 @@
     AlarmManager(IAlarmManager service, Context ctx) {
         mService = service;
 
+        mPackageName = ctx.getPackageName();
         mTargetSdkVersion = ctx.getApplicationInfo().targetSdkVersion;
         mAlwaysExact = (mTargetSdkVersion < Build.VERSION_CODES.KITKAT);
+        mMainThreadHandler = new Handler(ctx.getMainLooper());
     }
 
     private long legacyExactLength() {
@@ -249,7 +339,37 @@
      * @see #RTC_WAKEUP
      */
     public void set(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null);
+        setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, operation, null, null,
+                null, null, null);
+    }
+
+    /**
+     * Direct callback version of {@link #set(int, long, PendingIntent)}.  Rather than
+     * supplying a PendingIntent to be sent when the alarm time is reached, this variant
+     * supplies an {@link OnAlarmListener} instance that will be invoked at that time.
+     * <p>
+     * The OnAlarmListener's {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+     * invoked via the specified target Handler, or on the application's main looper
+     * if {@code null} is passed as the {@code targetHandler} parameter.
+     *
+     * @param type One of {@link #ELAPSED_REALTIME}, {@link #ELAPSED_REALTIME_WAKEUP},
+     *         {@link #RTC}, or {@link #RTC_WAKEUP}.
+     * @param triggerAtMillis time in milliseconds that the alarm should go
+     *         off, using the appropriate clock (depending on the alarm type).
+     * @param tag string describing the alarm, used for logging and battery-use
+     *         attribution
+     * @param listener {@link OnAlarmListener} instance whose
+     *         {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+     *         called when the alarm time is reached.  A given OnAlarmListener instance can
+     *         only be the target of a single pending alarm, just as a given PendingIntent
+     *         can only be used with one alarm at a time.
+     * @param targetHandler {@link Handler} on which to execute the listener's onAlarm()
+     *         callback, or {@code null} to run that callback on the main looper.
+     */
+    public void set(int type, long triggerAtMillis, String tag, OnAlarmListener listener,
+            Handler targetHandler) {
+        setImpl(type, triggerAtMillis, legacyExactLength(), 0, 0, null, listener, tag,
+                targetHandler, null, null);
     }
 
     /**
@@ -310,8 +430,8 @@
      */
     public void setRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation, null,
-                null);
+        setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, 0, operation,
+                null, null, null, null, null);
     }
 
     /**
@@ -361,7 +481,23 @@
      */
     public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
             PendingIntent operation) {
-        setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, operation, null, null);
+        setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, operation,
+                null, null, null, null, null);
+    }
+
+    /**
+     * Direct callback version of {@link #setWindow(int, long, long, PendingIntent)}.  Rather
+     * than supplying a PendingIntent to be sent when the alarm time is reached, this variant
+     * supplies an {@link OnAlarmListener} instance that will be invoked at that time.
+     * <p>
+     * The OnAlarmListener {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+     * invoked via the specified target Handler, or on the application's main looper
+     * if {@code null} is passed as the {@code targetHandler} parameter.
+     */
+    public void setWindow(int type, long windowStartMillis, long windowLengthMillis,
+            String tag, OnAlarmListener listener, Handler targetHandler) {
+        setImpl(type, windowStartMillis, windowLengthMillis, 0, 0, null, listener, tag,
+                targetHandler, null, null);
     }
 
     /**
@@ -399,7 +535,23 @@
      * @see #RTC_WAKEUP
      */
     public void setExact(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null);
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, operation, null, null, null,
+                null, null);
+    }
+
+    /**
+     * Direct callback version of {@link #setExact(int, long, PendingIntent)}.  Rather
+     * than supplying a PendingIntent to be sent when the alarm time is reached, this variant
+     * supplies an {@link OnAlarmListener} instance that will be invoked at that time.
+     * <p>
+     * The OnAlarmListener's {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+     * invoked via the specified target Handler, or on the application's main looper
+     * if {@code null} is passed as the {@code targetHandler} parameter.
+     */
+    public void setExact(int type, long triggerAtMillis, String tag, OnAlarmListener listener,
+            Handler targetHandler) {
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, 0, null, listener, tag,
+                targetHandler, null, null);
     }
 
     /**
@@ -408,7 +560,8 @@
      * @hide
      */
     public void setIdleUntil(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, operation, null, null);
+        setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_IDLE_UNTIL, operation,
+                null, null, null, null, null);
     }
 
     /**
@@ -436,19 +589,38 @@
      * @see android.content.Intent#filterEquals
      */
     public void setAlarmClock(AlarmClockInfo info, PendingIntent operation) {
-        setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, 0, operation, null, info);
+        setImpl(RTC_WAKEUP, info.getTriggerTime(), WINDOW_EXACT, 0, 0, operation,
+                null, null, null, null, info);
     }
 
     /** @hide */
     @SystemApi
     public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
             PendingIntent operation, WorkSource workSource) {
-        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, workSource,
-                null);
+        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, operation, null, null,
+                null, workSource, null);
+    }
+
+    /**
+     * Direct callback version of {@link #set(int, long, long, long, PendingIntent, WorkSource)}.
+     * Note that repeating alarms must use the PendingIntent variant, not an OnAlarmListener.
+     * <p>
+     * The OnAlarmListener's {@link OnAlarmListener#onAlarm() onAlarm()} method will be
+     * invoked via the specified target Handler, or on the application's main looper
+     * if {@code null} is passed as the {@code targetHandler} parameter.
+     *
+     * @hide
+     */
+    //@SystemApi
+    public void set(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
+            OnAlarmListener listener, Handler targetHandler, WorkSource workSource) {
+        setImpl(type, triggerAtMillis, windowMillis, intervalMillis, 0, null, listener, null,
+                targetHandler, workSource, null);
     }
 
     private void setImpl(int type, long triggerAtMillis, long windowMillis, long intervalMillis,
-            int flags, PendingIntent operation, WorkSource workSource, AlarmClockInfo alarmClock) {
+            int flags, PendingIntent operation, final OnAlarmListener listener, String listenerTag,
+            Handler targetHandler, WorkSource workSource, AlarmClockInfo alarmClock) {
         if (triggerAtMillis < 0) {
             /* NOTYET
             if (mAlwaysExact) {
@@ -460,9 +632,30 @@
             triggerAtMillis = 0;
         }
 
+        ListenerWrapper recipientWrapper = null;
+        if (listener != null) {
+            synchronized (AlarmManager.class) {
+                if (sWrappers == null) {
+                    sWrappers = new WeakHashMap<OnAlarmListener, WeakReference<ListenerWrapper>>();
+                }
+
+                WeakReference<ListenerWrapper> wrapperRef = sWrappers.get(listener);
+                // no existing wrapper *or* we've lost our weak ref to it => build a new one
+                if (wrapperRef == null ||
+                        (recipientWrapper = wrapperRef.get()) == null) {
+                    recipientWrapper = new ListenerWrapper(listener);
+                    wrapperRef = new WeakReference<ListenerWrapper>(recipientWrapper);
+                    sWrappers.put(listener, wrapperRef);
+                }
+            }
+
+            final Handler handler = (targetHandler != null) ? targetHandler : mMainThreadHandler;
+            recipientWrapper.setHandler(handler);
+        }
+
         try {
-            mService.set(type, triggerAtMillis, windowMillis, intervalMillis, flags, operation,
-                    workSource, alarmClock);
+            mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
+                    operation, recipientWrapper, listenerTag, workSource, alarmClock);
         } catch (RemoteException ex) {
         }
     }
@@ -562,7 +755,8 @@
      */
     public void setInexactRepeating(int type, long triggerAtMillis,
             long intervalMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null, null);
+        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, intervalMillis, 0, operation, null,
+                null, null, null, null);
     }
 
     /**
@@ -611,8 +805,8 @@
      * @see #RTC_WAKEUP
      */
     public void setAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
-        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE, operation,
-                null, null);
+        setImpl(type, triggerAtMillis, WINDOW_HEURISTIC, 0, FLAG_ALLOW_WHILE_IDLE,
+                operation, null, null, null, null, null);
     }
 
     /**
@@ -666,7 +860,7 @@
      */
     public void setExactAndAllowWhileIdle(int type, long triggerAtMillis, PendingIntent operation) {
         setImpl(type, triggerAtMillis, WINDOW_EXACT, 0, FLAG_ALLOW_WHILE_IDLE, operation,
-                null, null);
+                null, null, null, null, null);
     }
 
     /**
@@ -680,13 +874,44 @@
      * @see #set
      */
     public void cancel(PendingIntent operation) {
+        if (operation == null) {
+            throw new NullPointerException("operation");
+        }
+
         try {
-            mService.remove(operation);
+            mService.remove(operation, null);
         } catch (RemoteException ex) {
         }
     }
 
     /**
+     * Remove any alarm scheduled to be delivered to the given {@link OnAlarmListener}.
+     *
+     * @param listener OnAlarmListener instance that is the target of a currently-set alarm.
+     */
+    public void cancel(OnAlarmListener listener) {
+        if (listener == null) {
+            throw new NullPointerException("listener");
+        }
+
+        ListenerWrapper wrapper = null;
+        synchronized (AlarmManager.class) {
+            final WeakReference<ListenerWrapper> wrapperRef;
+            wrapperRef = sWrappers.get(listener);
+            if (wrapperRef != null) {
+                wrapper = wrapperRef.get();
+            }
+        }
+
+        if (wrapper == null) {
+            Log.w(TAG, "Unrecognized alarm listener " + listener);
+            return;
+        }
+
+        wrapper.cancel();
+    }
+
+    /**
      * Set the system wall clock time.
      * Requires the permission android.permission.SET_TIME.
      *
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c26a44c..fcc040b 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -123,7 +123,8 @@
     public void activitySlept(IBinder token) throws RemoteException;
     public void activityDestroyed(IBinder token) throws RemoteException;
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations) throws RemoteException;
+            int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
+            throws RemoteException;
     public String getCallingPackage(IBinder token) throws RemoteException;
     public ComponentName getCallingActivity(IBinder token) throws RemoteException;
     public List<IAppTask> getAppTasks(String callingPackage) throws RemoteException;
@@ -143,6 +144,7 @@
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop)
             throws RemoteException;
+    public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
     public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
     public List<StackInfo> getAllStackInfos() throws RemoteException;
@@ -898,4 +900,5 @@
     int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
     int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
     int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 348;
+    int MOVE_TOP_ACTIVITY_TO_PINNED_STACK = IBinder.FIRST_CALL_TRANSACTION + 349;
 }
diff --git a/core/java/android/app/IAlarmCompleteListener.aidl b/core/java/android/app/IAlarmCompleteListener.aidl
new file mode 100644
index 0000000..9f9ee40
--- /dev/null
+++ b/core/java/android/app/IAlarmCompleteListener.aidl
@@ -0,0 +1,27 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app;
+
+import android.os.IBinder;
+
+/**
+ * Callback from app into system process to indicate that processing of
+ * a direct-call alarm has completed.
+ * {@hide}
+ */
+interface IAlarmCompleteListener {
+    void alarmComplete(in IBinder who);
+}
diff --git a/core/java/android/app/IAlarmListener.aidl b/core/java/android/app/IAlarmListener.aidl
new file mode 100644
index 0000000..a110d4d
--- /dev/null
+++ b/core/java/android/app/IAlarmListener.aidl
@@ -0,0 +1,29 @@
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app;
+
+import android.app.IAlarmCompleteListener;
+
+/**
+ * System private API for direct alarm callbacks (non-broadcast deliver).  See the
+ * AlarmManager#set() variants that take an AlarmReceiver callback object
+ * rather than a PendingIntent.
+ *
+ * {@hide}
+ */
+oneway interface IAlarmListener {
+    void doAlarm(in IAlarmCompleteListener callback);
+}
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 327c00b..7b05b49 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -17,7 +17,9 @@
 package android.app;
 
 import android.app.AlarmManager;
+import android.app.IAlarmListener;
 import android.app.PendingIntent;
+import android.content.Intent;
 import android.os.WorkSource;
 
 /**
@@ -27,14 +29,12 @@
  */
 interface IAlarmManager {
 	/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
-    void set(int type, long triggerAtTime, long windowLength,
-            long interval, int flags, in PendingIntent operation, in WorkSource workSource,
-            in AlarmManager.AlarmClockInfo alarmClock);
+    void set(String callingPackage, int type, long triggerAtTime, long windowLength,
+            long interval, int flags, in PendingIntent operation, in IAlarmListener listener,
+            String listenerTag, in WorkSource workSource, in AlarmManager.AlarmClockInfo alarmClock);
     boolean setTime(long millis);
     void setTimeZone(String zone);
-    void remove(in PendingIntent operation);
+    void remove(in PendingIntent operation, in IAlarmListener listener);
     long getNextWakeFromIdleTime();
     AlarmManager.AlarmClockInfo getNextAlarmClock(int userId);
 }
-
-
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index e95a35a..30232da 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -83,10 +83,8 @@
 
     int getZenMode();
     ZenModeConfig getZenModeConfig();
-    boolean setZenModeConfig(in ZenModeConfig config, String reason);
     oneway void setZenMode(int mode, in Uri conditionId, String reason);
     oneway void notifyConditions(String pkg, in IConditionProvider provider, in Condition[] conditions);
-    oneway void requestZenModeConditions(in IConditionListener callback, int relevance);
     boolean isNotificationPolicyAccessGranted(String pkg);
     NotificationManager.Policy getNotificationPolicy(String pkg);
     void setNotificationPolicy(String pkg, in NotificationManager.Policy policy);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index db18722..49edff4 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -251,15 +251,26 @@
     public RemoteViews tickerView;
 
     /**
-     * The view that will represent this notification in the expanded status bar.
+     * The view that will represent this notification in the notification list (which is pulled
+     * down from the status bar).
+     *
+     * As of N, this field is not used. The notification view is determined by the inputs to
+     * {@link Notification.Builder}; a custom RemoteViews can optionally be
+     * supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
      */
+    @Deprecated
     public RemoteViews contentView;
 
     /**
      * A large-format version of {@link #contentView}, giving the Notification an
      * opportunity to show more detail. The system UI may choose to show this
      * instead of the normal content view at its discretion.
+     *
+     * As of N, this field is not used. The expanded notification view is determined by the
+     * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
+     * supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
      */
+    @Deprecated
     public RemoteViews bigContentView;
 
 
@@ -268,7 +279,12 @@
      * opportunity to add action buttons to contentView. At its discretion, the system UI may
      * choose to show this as a heads-up notification, which will pop up so the user can see
      * it without leaving their current activity.
+     *
+     * As of N, this field is not used. The heads-up notification view is determined by the
+     * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
+     * supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
      */
+    @Deprecated
     public RemoteViews headsUpContentView;
 
     /**
@@ -867,6 +883,11 @@
     public static final String EXTRA_ORIGINATING_USERID = "android.originatingUserId";
 
     /**
+     * @hide
+     */
+    public static final String EXTRA_BUILDER_APPLICATION_INFO = "android.appInfo";
+
+    /**
      * Value for {@link #EXTRA_AS_HEADS_UP} that indicates this notification should not be
      * displayed in the heads up space.
      *
@@ -1707,8 +1728,6 @@
             extras.remove(Notification.EXTRA_LARGE_ICON_BIG);
             extras.remove(Notification.EXTRA_PICTURE);
             extras.remove(Notification.EXTRA_BIG_TEXT);
-            // Prevent light notifications from being rebuilt.
-            extras.remove(Builder.EXTRA_NEEDS_REBUILD);
         }
     }
 
@@ -1901,21 +1920,13 @@
     @Deprecated
     public void setLatestEventInfo(Context context,
             CharSequence contentTitle, CharSequence contentText, PendingIntent contentIntent) {
-        Notification.Builder builder = new Notification.Builder(context);
+        if (context.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1){
+            Log.e(TAG, "setLatestEventInfo() is deprecated and you should feel deprecated.",
+                    new Throwable());
+        }
 
-        // First, ensure that key pieces of information that may have been set directly
-        // are preserved
-        builder.setWhen(this.when);
-        builder.setSmallIcon(this.icon);
-        builder.setPriority(this.priority);
-        builder.setTicker(this.tickerText);
-        builder.setNumber(this.number);
-        builder.setColor(this.color);
-        builder.mFlags = this.flags;
-        builder.setSound(this.sound, this.audioStreamType);
-        builder.setDefaults(this.defaults);
-        builder.setVibrate(this.vibrate);
-        builder.setDeleteIntent(this.deleteIntent);
+        // ensure that any information already set directly is preserved
+        final Notification.Builder builder = new Notification.Builder(context, this);
 
         // now apply the latestEventInfo fields
         if (contentTitle != null) {
@@ -1925,7 +1936,8 @@
             builder.setContentText(contentText);
         }
         builder.setContentIntent(contentIntent);
-        builder.buildInto(this);
+
+        builder.build(); // callers expect this notification to be ready to use
     }
 
     @Override
@@ -2080,15 +2092,6 @@
     /**
      * @hide
      */
-    public boolean isValid() {
-        // Would like to check for icon!=0 here, too, but NotificationManagerService accepts that
-        // for legacy reasons.
-        return contentView != null || extras.getBoolean(Builder.EXTRA_REBUILD_CONTENT_VIEW);
-    }
-
-    /**
-     * @hide
-     */
     public boolean isGroupSummary() {
         return mGroupKey != null && (flags & FLAG_GROUP_SUMMARY) != 0;
     }
@@ -2125,99 +2128,14 @@
         private static final int MAX_ACTION_BUTTONS = 3;
         private static final float LARGE_TEXT_SCALE = 1.3f;
 
-        /**
-         * @hide
-         */
-        public static final String EXTRA_NEEDS_REBUILD = "android.rebuild";
-
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_LARGE_ICON = "android.rebuild.largeIcon";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_CONTENT_VIEW = "android.rebuild.contentView";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT =
-                "android.rebuild.contentViewActionCount";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW
-                = "android.rebuild.bigView";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT
-                = "android.rebuild.bigViewActionCount";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW
-                = "android.rebuild.hudView";
-        /**
-         * @hide
-         */
-        public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT
-                = "android.rebuild.hudViewActionCount";
-
-        /**
-         * The ApplicationInfo of the package that created the notification, used to create
-         * a context to rebuild the notification via a Builder.
-         * @hide
-         */
-        private static final String EXTRA_REBUILD_CONTEXT_APPLICATION_INFO =
-                "android.rebuild.applicationInfo";
-
-        // Whether to enable stripping (at post time) & rebuilding (at listener receive time) of
-        // memory intensive resources.
-        private static final boolean STRIP_AND_REBUILD = true;
-
         private Context mContext;
-
-        private long mWhen;
-        private Icon mSmallIcon, mLargeIcon;
-        private int mSmallIconLevel;
-        private int mNumber;
-        private CharSequence mContentTitle;
-        private CharSequence mContentText;
-        private CharSequence mContentInfo;
-        private CharSequence mSubText;
-        private PendingIntent mContentIntent;
-        private RemoteViews mContentView;
-        private PendingIntent mDeleteIntent;
-        private PendingIntent mFullScreenIntent;
-        private CharSequence mTickerText;
-        private RemoteViews mTickerView;
-        private Uri mSound;
-        private int mAudioStreamType;
-        private AudioAttributes mAudioAttributes;
-        private long[] mVibrate;
-        private int mLedArgb;
-        private int mLedOnMs;
-        private int mLedOffMs;
-        private int mDefaults;
-        private int mFlags;
-        private int mProgressMax;
-        private int mProgress;
-        private boolean mProgressIndeterminate;
-        private String mCategory;
-        private String mGroupKey;
-        private String mSortKey;
-        private Bundle mExtras;
-        private int mPriority;
-        private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
-        private boolean mUseChronometer;
+        private Notification mN;
+        private Bundle mUserExtras = new Bundle();
         private Style mStyle;
-        private boolean mShowWhen = true;
-        private int mVisibility = VISIBILITY_PRIVATE;
-        private Notification mPublicVersion = null;
-        private final NotificationColorUtil mColorUtil;
-        private ArrayList<String> mPeople;
-        private int mColor = COLOR_DEFAULT;
+        private ArrayList<Action> mActions = new ArrayList<Action>(MAX_ACTION_BUTTONS);
+        private ArrayList<String> mPersonList = new ArrayList<String>();
+        private NotificationColorUtil mColorUtil;
+        private boolean mColorUtilInited = false;
         private List<Topic> mTopics = new ArrayList<>();
 
         /**
@@ -2226,25 +2144,6 @@
         private int mOriginatingUserId;
 
         /**
-         * Contains extras related to rebuilding during the build phase.
-         */
-        private Bundle mRebuildBundle = new Bundle();
-        /**
-         * Contains the notification to rebuild when this Builder is in "rebuild" mode.
-         * Null otherwise.
-         */
-        private Notification mRebuildNotification = null;
-
-        /**
-         * Whether the build notification has three lines. This is used to make the top padding for
-         * both the contracted and expanded layout consistent.
-         *
-         * <p>
-         * This field is only valid during the build phase.
-         */
-        private boolean mHasThreeLines;
-
-        /**
          * Constructs a new Builder with the defaults:
          *
 
@@ -2264,61 +2163,67 @@
          *            object.
          */
         public Builder(Context context) {
-            /*
-             * Important compatibility note!
-             * Some apps out in the wild create a Notification.Builder in their Activity subclass
-             * constructor for later use. At this point Activities - themselves subclasses of
-             * ContextWrapper - do not have their inner Context populated yet. This means that
-             * any calls to Context methods from within this constructor can cause NPEs in existing
-             * apps. Any data populated from mContext should therefore be populated lazily to
-             * preserve compatibility.
-             */
-            mContext = context;
-
-            // Set defaults to match the defaults of a Notification
-            mWhen = System.currentTimeMillis();
-            mAudioStreamType = STREAM_DEFAULT;
-            mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
-            mPriority = PRIORITY_DEFAULT;
-            mPeople = new ArrayList<String>();
-
-            mColorUtil = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP ?
-                    NotificationColorUtil.getInstance(mContext) : null;
+            this(context, null);
         }
 
         /**
-         * Creates a Builder for rebuilding the given Notification.
-         * <p>
-         * Call {@link #rebuild()} to retrieve the rebuilt version of 'n'.
+         * @hide
          */
-        private Builder(Context context, Notification n) {
-            this(context);
-            mRebuildNotification = n;
-            restoreFromNotification(n);
+        public Builder(Context context, Notification toAdopt) {
+            mContext = context;
 
-            Style style = null;
-            Bundle extras = n.extras;
-            String templateClass = extras.getString(EXTRA_TEMPLATE);
-            if (!TextUtils.isEmpty(templateClass)) {
-                Class<? extends Style> styleClass = getNotificationStyleClass(templateClass);
-                if (styleClass == null) {
-                    Log.d(TAG, "Unknown style class: " + styleClass);
-                    return;
+            if (toAdopt == null) {
+                mN = new Notification();
+                mN.extras.putBoolean(EXTRA_SHOW_WHEN, true);
+                mN.priority = PRIORITY_DEFAULT;
+                mN.visibility = VISIBILITY_PRIVATE;
+            } else {
+                mN = toAdopt;
+                if (mN.actions != null) {
+                    Collections.addAll(mActions, mN.actions);
                 }
 
-                try {
-                    Constructor<? extends Style> constructor = styleClass.getConstructor();
-                    constructor.setAccessible(true);
-                    style = constructor.newInstance();
-                    style.restoreFromExtras(extras);
-                } catch (Throwable t) {
-                    Log.e(TAG, "Could not create Style", t);
-                    return;
+                if (mN.extras.containsKey(EXTRA_PEOPLE)) {
+                    Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
+                }
+
+                if (mN.getTopics() != null) {
+                    Collections.addAll(mTopics, mN.getTopics());
+                }
+
+                String templateClass = mN.extras.getString(EXTRA_TEMPLATE);
+                if (!TextUtils.isEmpty(templateClass)) {
+                    final Class<? extends Style> styleClass
+                            = getNotificationStyleClass(templateClass);
+                    if (styleClass == null) {
+                        Log.d(TAG, "Unknown style class: " + templateClass);
+                    } else {
+                        try {
+                            final Constructor<? extends Style> ctor = styleClass.getConstructor();
+                            ctor.setAccessible(true);
+                            final Style style = ctor.newInstance();
+                            style.restoreFromExtras(mN.extras);
+
+                            if (style != null) {
+                                setStyle(style);
+                            }
+                        } catch (Throwable t) {
+                            Log.e(TAG, "Could not create Style", t);
+                        }
+                    }
+                }
+
+            }
+        }
+
+        private NotificationColorUtil getColorUtil() {
+            if (!mColorUtilInited) {
+                mColorUtilInited = true;
+                if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.LOLLIPOP) {
+                    mColorUtil = NotificationColorUtil.getInstance(mContext);
                 }
             }
-            if (style != null) {
-                setStyle(style);
-            }
+            return mColorUtil;
         }
 
         /**
@@ -2329,7 +2234,7 @@
          * @see Notification#when
          */
         public Builder setWhen(long when) {
-            mWhen = when;
+            mN.when = when;
             return this;
         }
 
@@ -2338,7 +2243,7 @@
          * in the content view.
          */
         public Builder setShowWhen(boolean show) {
-            mShowWhen = show;
+            mN.extras.putBoolean(EXTRA_SHOW_WHEN, show);
             return this;
         }
 
@@ -2354,7 +2259,7 @@
          * @see Notification#when
          */
         public Builder setUsesChronometer(boolean b) {
-            mUseChronometer = b;
+            mN.extras.putBoolean(EXTRA_SHOW_CHRONOMETER, b);
             return this;
         }
 
@@ -2390,7 +2295,7 @@
          * @see Notification#iconLevel
          */
         public Builder setSmallIcon(@DrawableRes int icon, int level) {
-            mSmallIconLevel = level;
+            mN.iconLevel = level;
             return setSmallIcon(icon);
         }
 
@@ -2403,7 +2308,10 @@
          * @see Notification#icon
          */
         public Builder setSmallIcon(Icon icon) {
-            mSmallIcon = icon;
+            mN.setSmallIcon(icon);
+            if (icon != null && icon.getType() == Icon.TYPE_RESOURCE) {
+                mN.icon = icon.getResId();
+            }
             return this;
         }
 
@@ -2411,7 +2319,7 @@
          * Set the first line of text in the platform notification template.
          */
         public Builder setContentTitle(CharSequence title) {
-            mContentTitle = safeCharSequence(title);
+            mN.extras.putCharSequence(EXTRA_TITLE, safeCharSequence(title));
             return this;
         }
 
@@ -2419,7 +2327,7 @@
          * Set the second line of text in the platform notification template.
          */
         public Builder setContentText(CharSequence text) {
-            mContentText = safeCharSequence(text);
+            mN.extras.putCharSequence(EXTRA_TEXT, safeCharSequence(text));
             return this;
         }
 
@@ -2429,7 +2337,7 @@
          * same location in the standard template.
          */
         public Builder setSubText(CharSequence text) {
-            mSubText = safeCharSequence(text);
+            mN.extras.putCharSequence(EXTRA_SUB_TEXT, safeCharSequence(text));
             return this;
         }
 
@@ -2439,7 +2347,7 @@
          * font size for readability.
          */
         public Builder setNumber(int number) {
-            mNumber = number;
+            mN.number = number;
             return this;
         }
 
@@ -2450,7 +2358,7 @@
          * right (to the right of a smallIcon if it has been placed there).
          */
         public Builder setContentInfo(CharSequence info) {
-            mContentInfo = safeCharSequence(info);
+            mN.extras.putCharSequence(EXTRA_INFO_TEXT, safeCharSequence(info));
             return this;
         }
 
@@ -2460,19 +2368,52 @@
          * The platform template will represent this using a {@link ProgressBar}.
          */
         public Builder setProgress(int max, int progress, boolean indeterminate) {
-            mProgressMax = max;
-            mProgress = progress;
-            mProgressIndeterminate = indeterminate;
+            mN.extras.putInt(EXTRA_PROGRESS, progress);
+            mN.extras.putInt(EXTRA_PROGRESS_MAX, max);
+            mN.extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, indeterminate);
             return this;
         }
 
         /**
          * Supply a custom RemoteViews to use instead of the platform template.
          *
-         * @see Notification#contentView
+         * Use {@link #setCustomContentView(RemoteViews)} instead.
          */
+        @Deprecated
         public Builder setContent(RemoteViews views) {
-            mContentView = views;
+            return setCustomContentView(views);
+        }
+
+        /**
+         * Supply custom RemoteViews to use instead of the platform template.
+         *
+         * This will override the layout that would otherwise be constructed by this Builder
+         * object.
+         */
+        public Builder setCustomContentView(RemoteViews contentView) {
+            mN.contentView = contentView;
+            return this;
+        }
+
+        /**
+         * Supply custom RemoteViews to use instead of the platform template in the expanded form.
+         *
+         * This will override the expanded layout that would otherwise be constructed by this
+         * Builder object.
+         */
+        public Builder setCustomBigContentView(RemoteViews contentView) {
+            mN.bigContentView = contentView;
+            return this;
+        }
+
+        /**
+         * Supply custom RemoteViews to use instead of the platform template in the heads up dialog.
+         *
+         * This will override the heads-up layout that would otherwise be constructed by this
+         * Builder object.
+         */
+        public Builder setCustomHeadsUpContentView(RemoteViews contentView) {
+            mN.headsUpContentView = contentView;
             return this;
         }
 
@@ -2488,7 +2429,7 @@
          * @see Notification#contentIntent Notification.contentIntent
          */
         public Builder setContentIntent(PendingIntent intent) {
-            mContentIntent = intent;
+            mN.contentIntent = intent;
             return this;
         }
 
@@ -2498,7 +2439,7 @@
          * @see Notification#deleteIntent
          */
         public Builder setDeleteIntent(PendingIntent intent) {
-            mDeleteIntent = intent;
+            mN.deleteIntent = intent;
             return this;
         }
 
@@ -2523,7 +2464,7 @@
          * @see Notification#fullScreenIntent
          */
         public Builder setFullScreenIntent(PendingIntent intent, boolean highPriority) {
-            mFullScreenIntent = intent;
+            mN.fullScreenIntent = intent;
             setFlag(FLAG_HIGH_PRIORITY, highPriority);
             return this;
         }
@@ -2534,7 +2475,7 @@
          * @see Notification#tickerText
          */
         public Builder setTicker(CharSequence tickerText) {
-            mTickerText = safeCharSequence(tickerText);
+            mN.tickerText = safeCharSequence(tickerText);
             return this;
         }
 
@@ -2544,8 +2485,8 @@
          */
         @Deprecated
         public Builder setTicker(CharSequence tickerText, RemoteViews views) {
-            mTickerText = safeCharSequence(tickerText);
-            mTickerView = views; // we'll save it for you anyway
+            setTicker(tickerText);
+            // views is ignored
             return this;
         }
 
@@ -2568,7 +2509,8 @@
          * badge atop the large icon).
          */
         public Builder setLargeIcon(Icon icon) {
-            mLargeIcon = icon;
+            mN.mLargeIcon = icon;
+            mN.extras.putParcelable(EXTRA_LARGE_ICON, icon);
             return this;
         }
 
@@ -2585,8 +2527,8 @@
          * @see Notification#sound
          */
         public Builder setSound(Uri sound) {
-            mSound = sound;
-            mAudioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
+            mN.sound = sound;
+            mN.audioAttributes = AUDIO_ATTRIBUTES_DEFAULT;
             return this;
         }
 
@@ -2603,8 +2545,8 @@
          */
         @Deprecated
         public Builder setSound(Uri sound, int streamType) {
-            mSound = sound;
-            mAudioStreamType = streamType;
+            mN.sound = sound;
+            mN.audioStreamType = streamType;
             return this;
         }
 
@@ -2619,8 +2561,8 @@
          * @see Notification#sound
          */
         public Builder setSound(Uri sound, AudioAttributes audioAttributes) {
-            mSound = sound;
-            mAudioAttributes = audioAttributes;
+            mN.sound = sound;
+            mN.audioAttributes = audioAttributes;
             return this;
         }
 
@@ -2637,7 +2579,7 @@
          * @see Notification#vibrate
          */
         public Builder setVibrate(long[] pattern) {
-            mVibrate = pattern;
+            mN.vibrate = pattern;
             return this;
         }
 
@@ -2654,9 +2596,9 @@
          * @see Notification#ledOffMS
          */
         public Builder setLights(@ColorInt int argb, int onMs, int offMs) {
-            mLedArgb = argb;
-            mLedOnMs = onMs;
-            mLedOffMs = offMs;
+            mN.ledARGB = argb;
+            mN.ledOnMS = onMs;
+            mN.ledOffMS = offMs;
             return this;
         }
 
@@ -2724,7 +2666,7 @@
          * For all default values, use {@link #DEFAULT_ALL}.
          */
         public Builder setDefaults(int defaults) {
-            mDefaults = defaults;
+            mN.defaults = defaults;
             return this;
         }
 
@@ -2734,7 +2676,7 @@
          * @see Notification#priority
          */
         public Builder setPriority(@Priority int pri) {
-            mPriority = pri;
+            mN.priority = pri;
             return this;
         }
 
@@ -2744,7 +2686,7 @@
          * @see Notification#category
          */
         public Builder setCategory(String category) {
-            mCategory = category;
+            mN.category = category;
             return this;
         }
 
@@ -2771,7 +2713,7 @@
          * @see Notification#EXTRA_PEOPLE
          */
         public Builder addPerson(String uri) {
-            mPeople.add(uri);
+            mPersonList.add(uri);
             return this;
         }
 
@@ -2787,7 +2729,7 @@
          * @return this object for method chaining
          */
         public Builder setGroup(String groupKey) {
-            mGroupKey = groupKey;
+            mN.mGroupKey = groupKey;
             return this;
         }
 
@@ -2816,7 +2758,7 @@
          * @see String#compareTo(String)
          */
         public Builder setSortKey(String sortKey) {
-            mSortKey = sortKey;
+            mN.mSortKey = sortKey;
             return this;
         }
 
@@ -2829,11 +2771,7 @@
          */
         public Builder addExtras(Bundle extras) {
             if (extras != null) {
-                if (mExtras == null) {
-                    mExtras = new Bundle(extras);
-                } else {
-                    mExtras.putAll(extras);
-                }
+                mUserExtras.putAll(extras);
             }
             return this;
         }
@@ -2851,7 +2789,9 @@
          * @see Notification#extras
          */
         public Builder setExtras(Bundle extras) {
-            mExtras = extras;
+            if (extras != null) {
+                mUserExtras = extras;
+            }
             return this;
         }
 
@@ -2866,10 +2806,13 @@
          * @see Notification#extras
          */
         public Bundle getExtras() {
-            if (mExtras == null) {
-                mExtras = new Bundle();
-            }
-            return mExtras;
+            return mUserExtras;
+        }
+
+        private Bundle getAllExtras() {
+            final Bundle saveExtras = (Bundle) mUserExtras.clone();
+            saveExtras.putAll(mN.extras);
+            return saveExtras;
         }
 
         /**
@@ -2918,6 +2861,21 @@
         }
 
         /**
+         * Alter the complete list of actions attached to this notification.
+         * @see #addAction(Action).
+         *
+         * @param actions
+         * @return
+         */
+        public Builder setActions(Action... actions) {
+            mActions.clear();
+            for (int i = 0; i < actions.length; i++) {
+                mActions.add(actions[i]);
+            }
+            return this;
+        }
+
+        /**
          * Add a rich notification style to be applied at build time.
          *
          * @param style Object responsible for modifying the notification style.
@@ -2927,6 +2885,9 @@
                 mStyle = style;
                 if (mStyle != null) {
                     mStyle.setBuilder(this);
+                    mN.extras.putString(EXTRA_TEMPLATE, style.getClass().getName());
+                }  else {
+                    mN.extras.remove(EXTRA_TEMPLATE);
                 }
             }
             return this;
@@ -2941,7 +2902,7 @@
          * @return The same Builder.
          */
         public Builder setVisibility(int visibility) {
-            mVisibility = visibility;
+            mN.visibility = visibility;
             return this;
         }
 
@@ -2952,7 +2913,12 @@
          * @return The same Builder.
          */
         public Builder setPublicVersion(Notification n) {
-            mPublicVersion = n;
+            if (n != null) {
+                mN.publicVersion = new Notification();
+                n.cloneInto(mN.publicVersion, /*heavy=*/ true);
+            } else {
+                mN.publicVersion = null;
+            }
             return this;
         }
 
@@ -2970,9 +2936,9 @@
          */
         public void setFlag(int mask, boolean value) {
             if (value) {
-                mFlags |= mask;
+                mN.flags |= mask;
             } else {
-                mFlags &= ~mask;
+                mN.flags &= ~mask;
             }
         }
 
@@ -2984,7 +2950,7 @@
          * @return The same Builder.
          */
         public Builder setColor(@ColorInt int argb) {
-            mColor = argb;
+            mN.color = argb;
             return this;
         }
 
@@ -3075,7 +3041,6 @@
             contentView.setViewVisibility(R.id.overflow_divider, View.GONE);
             contentView.setViewVisibility(R.id.progress, View.GONE);
             contentView.setViewVisibility(R.id.chronometer, View.GONE);
-            contentView.setViewVisibility(R.id.time, View.GONE);
         }
 
         private RemoteViews applyStandardTemplate(int resId) {
@@ -3093,39 +3058,43 @@
             boolean showLine3 = false;
             boolean showLine2 = false;
             boolean contentTextInLine2 = false;
+            final Bundle ex = mN.extras;
 
-            if (mLargeIcon != null) {
-                contentView.setImageViewIcon(R.id.icon, mLargeIcon);
-                processLargeLegacyIcon(mLargeIcon, contentView);
-                contentView.setImageViewIcon(R.id.right_icon, mSmallIcon);
+            if (mN.mLargeIcon != null) {
+                contentView.setImageViewIcon(R.id.icon, mN.mLargeIcon);
+                processLargeLegacyIcon(mN.mLargeIcon, contentView);
+                contentView.setImageViewIcon(R.id.right_icon, mN.mSmallIcon);
                 contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
-                processSmallRightIcon(mSmallIcon, contentView);
+                processSmallRightIcon(mN.mSmallIcon, contentView);
             } else { // small icon at left
-                contentView.setImageViewIcon(R.id.icon, mSmallIcon);
+                contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
                 contentView.setViewVisibility(R.id.icon, View.VISIBLE);
-                processSmallIconAsLarge(mSmallIcon, contentView);
+                processSmallIconAsLarge(mN.mSmallIcon, contentView);
             }
-            if (mContentTitle != null) {
-                contentView.setTextViewText(R.id.title, processLegacyText(mContentTitle));
+            if (ex.getCharSequence(EXTRA_TITLE) != null) {
+                contentView.setTextViewText(R.id.title,
+                        processLegacyText(ex.getCharSequence(EXTRA_TITLE)));
             }
-            if (mContentText != null) {
-                contentView.setTextViewText(R.id.text, processLegacyText(mContentText));
+            if (ex.getCharSequence(EXTRA_TEXT) != null) {
+                contentView.setTextViewText(R.id.text,
+                        processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
                 showLine3 = true;
             }
-            if (mContentInfo != null) {
-                contentView.setTextViewText(R.id.info, processLegacyText(mContentInfo));
+            if (ex.getCharSequence(EXTRA_INFO_TEXT) != null) {
+                contentView.setTextViewText(R.id.info,
+                        processLegacyText(ex.getCharSequence(EXTRA_INFO_TEXT)));
                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
                 showLine3 = true;
-            } else if (mNumber > 0) {
+            } else if (mN.number > 0) {
                 final int tooBig = mContext.getResources().getInteger(
                         R.integer.status_bar_notification_info_maxnum);
-                if (mNumber > tooBig) {
+                if (mN.number > tooBig) {
                     contentView.setTextViewText(R.id.info, processLegacyText(
                             mContext.getResources().getString(
                                     R.string.status_bar_notification_info_overflow)));
                 } else {
                     NumberFormat f = NumberFormat.getIntegerInstance();
-                    contentView.setTextViewText(R.id.info, processLegacyText(f.format(mNumber)));
+                    contentView.setTextViewText(R.id.info, processLegacyText(f.format(mN.number)));
                 }
                 contentView.setViewVisibility(R.id.info, View.VISIBLE);
                 showLine3 = true;
@@ -3134,10 +3103,12 @@
             }
 
             // Need to show three lines?
-            if (mSubText != null) {
-                contentView.setTextViewText(R.id.text, processLegacyText(mSubText));
-                if (mContentText != null) {
-                    contentView.setTextViewText(R.id.text2, processLegacyText(mContentText));
+            if (ex.getCharSequence(EXTRA_SUB_TEXT) != null) {
+                contentView.setTextViewText(R.id.text,
+                        processLegacyText(ex.getCharSequence(EXTRA_SUB_TEXT)));
+                if (ex.getCharSequence(EXTRA_TEXT) != null) {
+                    contentView.setTextViewText(R.id.text2,
+                            processLegacyText(ex.getCharSequence(EXTRA_TEXT)));
                     contentView.setViewVisibility(R.id.text2, View.VISIBLE);
                     showLine2 = true;
                     contentTextInLine2 = true;
@@ -3146,15 +3117,18 @@
                 }
             } else {
                 contentView.setViewVisibility(R.id.text2, View.GONE);
-                if (hasProgress && (mProgressMax != 0 || mProgressIndeterminate)) {
+                final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
+                final int progress = ex.getInt(EXTRA_PROGRESS, 0);
+                final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+                if (hasProgress && (max != 0 || ind)) {
                     contentView.setViewVisibility(R.id.progress, View.VISIBLE);
                     contentView.setProgressBar(
-                            R.id.progress, mProgressMax, mProgress, mProgressIndeterminate);
+                            R.id.progress, max, progress, ind);
                     contentView.setProgressBackgroundTintList(
                             R.id.progress, ColorStateList.valueOf(mContext.getColor(
                                     R.color.notification_progress_background_color)));
-                    if (mColor != COLOR_DEFAULT) {
-                        ColorStateList colorStateList = ColorStateList.valueOf(mColor);
+                    if (mN.color != COLOR_DEFAULT) {
+                        ColorStateList colorStateList = ColorStateList.valueOf(mN.color);
                         contentView.setProgressTintList(R.id.progress, colorStateList);
                         contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList);
                     }
@@ -3170,20 +3144,21 @@
             }
 
             if (showsTimeOrChronometer()) {
-                if (mUseChronometer) {
+                if (ex.getBoolean(EXTRA_SHOW_CHRONOMETER)) {
                     contentView.setViewVisibility(R.id.chronometer, View.VISIBLE);
                     contentView.setLong(R.id.chronometer, "setBase",
-                            mWhen + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
+                            mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
                 } else {
                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
-                    contentView.setLong(R.id.time, "setTime", mWhen);
+                    contentView.setLong(R.id.time, "setTime", mN.when);
                 }
             }
 
             // Adjust padding depending on line count and font size.
-            contentView.setViewPadding(R.id.line1, 0, calculateTopPadding(mContext,
-                    mHasThreeLines, mContext.getResources().getConfiguration().fontScale),
+            contentView.setViewPadding(R.id.line1, 0,
+                    calculateTopPadding(mContext, hasThreeLines(),
+                            mContext.getResources().getConfiguration().fontScale),
                     0, 0);
 
             // We want to add badge to first line of text.
@@ -3196,7 +3171,8 @@
 
             // Note getStandardView may hide line 3 again.
             contentView.setViewVisibility(R.id.line3, showLine3 ? View.VISIBLE : View.GONE);
-            contentView.setViewVisibility(R.id.overflow_divider, showLine3 ? View.VISIBLE : View.GONE);
+            contentView.setViewVisibility(R.id.overflow_divider,
+                    showLine3 ? View.VISIBLE : View.GONE);
             return contentView;
         }
 
@@ -3205,7 +3181,7 @@
          *         otherwise
          */
         private boolean showsTimeOrChronometer() {
-            return mWhen != 0 && mShowWhen;
+            return mN.when != 0 && mN.extras.getBoolean(EXTRA_SHOW_WHEN);
         }
 
         /**
@@ -3216,15 +3192,19 @@
          *         is going to have one or two lines
          */
         private boolean hasThreeLines() {
-            boolean contentTextInLine2 = mSubText != null && mContentText != null;
+            final CharSequence subText = mN.extras.getCharSequence(EXTRA_SUB_TEXT);
+            final CharSequence text = mN.extras.getCharSequence(EXTRA_TEXT);
+            boolean contentTextInLine2 = subText != null && text != null;
             boolean hasProgress = mStyle == null || mStyle.hasProgress();
             // If we have content text in line 2, badge goes into line 2, or line 3 otherwise
             boolean badgeInLine3 = getProfileBadgeDrawable() != null && !contentTextInLine2;
-            boolean hasLine3 = mContentText != null || mContentInfo != null || mNumber > 0
-                    || badgeInLine3;
-            boolean hasLine2 = (mSubText != null && mContentText != null) ||
-                    (hasProgress && mSubText == null
-                            && (mProgressMax != 0 || mProgressIndeterminate));
+            boolean hasLine3 = text != null || mN.extras.getCharSequence(EXTRA_INFO_TEXT) != null
+                    || mN.number > 0 || badgeInLine3;
+            final Bundle ex = mN.extras;
+            final int max = ex.getInt(EXTRA_PROGRESS_MAX, 0);
+            final boolean ind = ex.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
+            boolean hasLine2 = (subText != null && text != null) ||
+                    (hasProgress && subText == null && (max != 0 || ind));
             return hasLine2 && hasLine3;
         }
 
@@ -3271,29 +3251,48 @@
             return big;
         }
 
-        private RemoteViews makeContentView() {
-            if (mContentView != null) {
-                return mContentView;
-            } else {
-                return applyStandardTemplate(getBaseLayoutResource());
+        /**
+         * Construct a RemoteViews for the final 1U notification layout. In order:
+         *   1. Custom contentView from the caller
+         *   2. Style's proposed content view
+         *   3. Standard template view
+         */
+        public RemoteViews makeContentView() {
+            if (mN.contentView != null) {
+                return mN.contentView;
+            } else if (mStyle != null) {
+                final RemoteViews styleView = mStyle.makeContentView();
+                if (styleView != null) {
+                    return styleView;
+                }
             }
+            return applyStandardTemplate(getBaseLayoutResource());
         }
 
-        private RemoteViews makeTickerView() {
-            if (mTickerView != null) {
-                return mTickerView;
-            }
-            return null; // tickers are not created by default anymore
-        }
-
-        private RemoteViews makeBigContentView() {
-            if (mActions.size() == 0) return null;
+        /**
+         * Construct a RemoteViews for the final big notification layout.
+         */
+        public RemoteViews makeBigContentView() {
+            if (mStyle != null) {
+                final RemoteViews styleView = mStyle.makeBigContentView();
+                if (styleView != null) {
+                    return styleView;
+                }
+            } else if (mActions.size() == 0) return null;
 
             return applyStandardTemplateWithActions(getBigBaseLayoutResource());
         }
 
-        private RemoteViews makeHeadsUpContentView() {
-            if (mActions.size() == 0) return null;
+        /**
+         * Construct a RemoteViews for the final heads-up notification layout.
+         */
+        public RemoteViews makeHeadsUpContentView() {
+            if (mStyle != null) {
+                final RemoteViews styleView = mStyle.makeHeadsUpContentView();
+                if (styleView != null) {
+                    return styleView;
+                }
+            } else if (mActions.size() == 0) return null;
 
             return applyStandardTemplateWithActions(getBigBaseLayoutResource());
         }
@@ -3320,11 +3319,11 @@
          *         doesn't create material notifications by itself) app.
          */
         private boolean isLegacy() {
-            return mColorUtil != null;
+            return getColorUtil() != null;
         }
 
         private void processLegacyAction(Action action, RemoteViews button) {
-            if (!isLegacy() || mColorUtil.isGrayscaleIcon(mContext, action.getIcon())) {
+            if (!isLegacy() || getColorUtil().isGrayscaleIcon(mContext, action.getIcon())) {
                 button.setTextViewCompoundDrawablesRelativeColorFilter(R.id.action0, 0,
                         mContext.getColor(R.color.notification_action_color_filter),
                         PorterDuff.Mode.MULTIPLY);
@@ -3333,7 +3332,7 @@
 
         private CharSequence processLegacyText(CharSequence charSequence) {
             if (isLegacy()) {
-                return mColorUtil.invertCharSequenceColors(charSequence);
+                return getColorUtil().invertCharSequenceColors(charSequence);
             } else {
                 return charSequence;
             }
@@ -3349,7 +3348,7 @@
                         PorterDuff.Mode.SRC_ATOP, -1);
                 applyLargeIconBackground(contentView);
             } else {
-                if (mColorUtil.isGrayscaleIcon(mContext, largeIcon)) {
+                if (getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                     applyLargeIconBackground(contentView);
                 }
             }
@@ -3362,7 +3361,7 @@
         // TODO: also check bounds, transparency, that sort of thing.
         private void processLargeLegacyIcon(Icon largeIcon, RemoteViews contentView) {
             if (largeIcon != null && isLegacy()
-                    && mColorUtil.isGrayscaleIcon(mContext, largeIcon)) {
+                    && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 applyLargeIconBackground(contentView);
             } else {
                 removeLargeIconBackground(contentView);
@@ -3404,7 +3403,7 @@
             }
             final boolean gray = isLegacy()
                     && smallIcon.getType() == Icon.TYPE_RESOURCE
-                    && mColorUtil.isGrayscaleIcon(mContext, smallIcon.getResId());
+                    && getColorUtil().isGrayscaleIcon(mContext, smallIcon.getResId());
             if (!isLegacy() || gray) {
                 contentView.setInt(R.id.right_icon,
                         "setBackgroundResource",
@@ -3421,17 +3420,17 @@
         }
 
         private int sanitizeColor() {
-            if (mColor != COLOR_DEFAULT) {
-                mColor |= 0xFF000000; // no alpha for custom colors
+            if (mN.color != COLOR_DEFAULT) {
+                mN.color |= 0xFF000000; // no alpha for custom colors
             }
-            return mColor;
+            return mN.color;
         }
 
         private int resolveColor() {
-            if (mColor == COLOR_DEFAULT) {
+            if (mN.color == COLOR_DEFAULT) {
                 return mContext.getColor(R.color.notification_icon_bg_color);
             }
-            return mColor;
+            return mN.color;
         }
 
         /**
@@ -3439,165 +3438,25 @@
          * @hide
          */
         public Notification buildUnstyled() {
-            Notification n = new Notification();
-            n.when = mWhen;
-            n.mSmallIcon = mSmallIcon;
-            if (mSmallIcon != null && mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
-                n.icon = mSmallIcon.getResId();
-            }
-            n.iconLevel = mSmallIconLevel;
-            n.number = mNumber;
-
-            n.color = sanitizeColor();
-
-            setBuilderContentView(n, makeContentView());
-            n.contentIntent = mContentIntent;
-            n.deleteIntent = mDeleteIntent;
-            n.fullScreenIntent = mFullScreenIntent;
-            n.tickerText = mTickerText;
-            n.tickerView = makeTickerView();
-            n.mLargeIcon = mLargeIcon;
-            if (mLargeIcon != null && mLargeIcon.getType() == Icon.TYPE_BITMAP) {
-                n.largeIcon = mLargeIcon.getBitmap();
-            }
-            n.sound = mSound;
-            n.audioStreamType = mAudioStreamType;
-            n.audioAttributes = mAudioAttributes;
-            n.vibrate = mVibrate;
-            n.ledARGB = mLedArgb;
-            n.ledOnMS = mLedOnMs;
-            n.ledOffMS = mLedOffMs;
-            n.defaults = mDefaults;
-            n.flags = mFlags;
-            setBuilderBigContentView(n, makeBigContentView());
-            setBuilderHeadsUpContentView(n, makeHeadsUpContentView());
-            if (mLedOnMs != 0 || mLedOffMs != 0) {
-                n.flags |= FLAG_SHOW_LIGHTS;
-            }
-            if ((mDefaults & DEFAULT_LIGHTS) != 0) {
-                n.flags |= FLAG_SHOW_LIGHTS;
-            }
-            n.category = mCategory;
-            n.mGroupKey = mGroupKey;
-            n.mSortKey = mSortKey;
-            n.priority = mPriority;
             if (mActions.size() > 0) {
-                n.actions = new Action[mActions.size()];
-                mActions.toArray(n.actions);
+                mN.actions = new Action[mActions.size()];
+                mActions.toArray(mN.actions);
             }
-            n.visibility = mVisibility;
-
-            if (mPublicVersion != null) {
-                n.publicVersion = new Notification();
-                mPublicVersion.cloneInto(n.publicVersion, true);
+            if (!mPersonList.isEmpty()) {
+                mN.extras.putStringArray(EXTRA_PEOPLE,
+                        mPersonList.toArray(new String[mPersonList.size()]));
             }
             if (mTopics.size() > 0) {
-                n.topics = new Topic[mTopics.size()];
-                mTopics.toArray(n.topics);
+                mN.topics = new Topic[mTopics.size()];
+                mTopics.toArray(mN.topics);
             }
-            // Note: If you're adding new fields, also update restoreFromNotitification().
-            return n;
+            return mN;
         }
 
-        /**
-         * Capture, in the provided bundle, semantic information used in the construction of
-         * this Notification object.
-         * @hide
-         */
-        public void populateExtras(Bundle extras) {
-            // Store original information used in the construction of this object
-            extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
-            extras.putParcelable(EXTRA_REBUILD_CONTEXT_APPLICATION_INFO,
-                    mContext.getApplicationInfo());
-            extras.putCharSequence(EXTRA_TITLE, mContentTitle);
-            extras.putCharSequence(EXTRA_TEXT, mContentText);
-            extras.putCharSequence(EXTRA_SUB_TEXT, mSubText);
-            extras.putCharSequence(EXTRA_INFO_TEXT, mContentInfo);
-            extras.putParcelable(EXTRA_SMALL_ICON, mSmallIcon);
-            extras.putInt(EXTRA_PROGRESS, mProgress);
-            extras.putInt(EXTRA_PROGRESS_MAX, mProgressMax);
-            extras.putBoolean(EXTRA_PROGRESS_INDETERMINATE, mProgressIndeterminate);
-            extras.putBoolean(EXTRA_SHOW_CHRONOMETER, mUseChronometer);
-            extras.putBoolean(EXTRA_SHOW_WHEN, mShowWhen);
-            if (mLargeIcon != null) {
-                extras.putParcelable(EXTRA_LARGE_ICON, mLargeIcon);
-            }
-            if (!mPeople.isEmpty()) {
-                extras.putStringArray(EXTRA_PEOPLE, mPeople.toArray(new String[mPeople.size()]));
-            }
-            // NOTE: If you're adding new extras also update restoreFromNotification().
-        }
-
-
-        /**
-         * @hide
-         */
-        public static void stripForDelivery(Notification n) {
-            if (!STRIP_AND_REBUILD) {
-                return;
-            }
-
-            String templateClass = n.extras.getString(EXTRA_TEMPLATE);
-            // Only strip views for known Styles because we won't know how to
-            // re-create them otherwise.
-            boolean stripViews = TextUtils.isEmpty(templateClass) ||
-                    getNotificationStyleClass(templateClass) != null;
-
-            boolean isStripped = false;
-
-            if (n.largeIcon != null && n.extras.containsKey(EXTRA_LARGE_ICON)) {
-                // TODO: Would like to check for equality here, but if the notification
-                // has been cloned, we can't.
-                n.largeIcon = null;
-                n.extras.putBoolean(EXTRA_REBUILD_LARGE_ICON, true);
-                isStripped = true;
-            }
-            // Get rid of unmodified BuilderRemoteViews.
-
-            if (stripViews &&
-                    n.contentView instanceof BuilderRemoteViews &&
-                    n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.contentView.getSequenceNumber()) {
-                n.contentView = null;
-                n.extras.putBoolean(EXTRA_REBUILD_CONTENT_VIEW, true);
-                n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
-                isStripped = true;
-            }
-            if (stripViews &&
-                    n.bigContentView instanceof BuilderRemoteViews &&
-                    n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.bigContentView.getSequenceNumber()) {
-                n.bigContentView = null;
-                n.extras.putBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW, true);
-                n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
-                isStripped = true;
-            }
-            if (stripViews &&
-                    n.headsUpContentView instanceof BuilderRemoteViews &&
-                    n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
-                            n.headsUpContentView.getSequenceNumber()) {
-                n.headsUpContentView = null;
-                n.extras.putBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW, true);
-                n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
-                isStripped = true;
-            }
-
-            if (isStripped) {
-                n.extras.putBoolean(EXTRA_NEEDS_REBUILD, true);
-            }
-        }
-
-        /**
-         * @hide
-         */
-        public static Notification rebuild(Context context, Notification n) {
-            Bundle extras = n.extras;
-            if (!extras.getBoolean(EXTRA_NEEDS_REBUILD)) return n;
-            extras.remove(EXTRA_NEEDS_REBUILD);
-
+        public static Notification.Builder recoverBuilder(Context context, Notification n) {
             // Re-create notification context so we can access app resources.
-            ApplicationInfo applicationInfo = extras.getParcelable(
-                    EXTRA_REBUILD_CONTEXT_APPLICATION_INFO);
+            ApplicationInfo applicationInfo = n.extras.getParcelable(
+                    EXTRA_BUILDER_APPLICATION_INFO);
             Context builderContext;
             try {
                 builderContext = context.createApplicationContext(applicationInfo,
@@ -3607,58 +3466,7 @@
                 builderContext = context;  // try with our context
             }
 
-            Builder b = new Builder(builderContext, n);
-            return b.rebuild();
-        }
-
-        /**
-         * Rebuilds the notification passed in to the rebuild-constructor
-         * {@link #Builder(Context, Notification)}.
-         *
-         * <p>
-         * Throws IllegalStateException when invoked on a Builder that isn't in rebuild mode.
-         *
-         * @hide
-         */
-        private Notification rebuild() {
-            if (mRebuildNotification == null) {
-                throw new IllegalStateException("rebuild() only valid when in 'rebuild' mode.");
-            }
-            mHasThreeLines = hasThreeLines();
-
-            Bundle extras = mRebuildNotification.extras;
-
-            if (extras.getBoolean(EXTRA_REBUILD_LARGE_ICON)) {
-                mRebuildNotification.largeIcon = extras.getParcelable(EXTRA_LARGE_ICON);
-            }
-            extras.remove(EXTRA_REBUILD_LARGE_ICON);
-
-            if (extras.getBoolean(EXTRA_REBUILD_CONTENT_VIEW)) {
-                setBuilderContentView(mRebuildNotification, makeContentView());
-                if (mStyle != null) {
-                    mStyle.populateContentView(mRebuildNotification);
-                }
-            }
-            extras.remove(EXTRA_REBUILD_CONTENT_VIEW);
-
-            if (extras.getBoolean(EXTRA_REBUILD_BIG_CONTENT_VIEW)) {
-                setBuilderBigContentView(mRebuildNotification, makeBigContentView());
-                if (mStyle != null) {
-                    mStyle.populateBigContentView(mRebuildNotification);
-                }
-            }
-            extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW);
-
-            if (extras.getBoolean(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW)) {
-                setBuilderHeadsUpContentView(mRebuildNotification, makeHeadsUpContentView());
-                if (mStyle != null) {
-                    mStyle.populateHeadsUpContentView(mRebuildNotification);
-                }
-            }
-            extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW);
-
-            mHasThreeLines = false;
-            return mRebuildNotification;
+            return new Builder(builderContext, n);
         }
 
         private static Class<? extends Style> getNotificationStyleClass(String templateClass) {
@@ -3674,91 +3482,15 @@
 
         private void setBuilderContentView(Notification n, RemoteViews contentView) {
             n.contentView = contentView;
-            if (contentView instanceof BuilderRemoteViews) {
-                mRebuildBundle.putInt(Builder.EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
-                        contentView.getSequenceNumber());
-            }
         }
 
         private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
             n.bigContentView = bigContentView;
-            if (bigContentView instanceof BuilderRemoteViews) {
-                mRebuildBundle.putInt(Builder.EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
-                        bigContentView.getSequenceNumber());
-            }
         }
 
         private void setBuilderHeadsUpContentView(Notification n,
                 RemoteViews headsUpContentView) {
             n.headsUpContentView = headsUpContentView;
-            if (headsUpContentView instanceof BuilderRemoteViews) {
-                mRebuildBundle.putInt(Builder.EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
-                        headsUpContentView.getSequenceNumber());
-            }
-        }
-
-        private void restoreFromNotification(Notification n) {
-
-            // Notification fields.
-            mWhen = n.when;
-            mSmallIcon = n.mSmallIcon;
-            mSmallIconLevel = n.iconLevel;
-            mNumber = n.number;
-
-            mColor = n.color;
-
-            mContentView = n.contentView;
-            mDeleteIntent = n.deleteIntent;
-            mFullScreenIntent = n.fullScreenIntent;
-            mTickerText = n.tickerText;
-            mTickerView = n.tickerView;
-            mLargeIcon = n.mLargeIcon;
-            mSound = n.sound;
-            mAudioStreamType = n.audioStreamType;
-            mAudioAttributes = n.audioAttributes;
-
-            mVibrate = n.vibrate;
-            mLedArgb = n.ledARGB;
-            mLedOnMs = n.ledOnMS;
-            mLedOffMs = n.ledOffMS;
-            mDefaults = n.defaults;
-            mFlags = n.flags;
-
-            mCategory = n.category;
-            mGroupKey = n.mGroupKey;
-            mSortKey = n.mSortKey;
-            mPriority = n.priority;
-            mActions.clear();
-            if (n.actions != null) {
-                Collections.addAll(mActions, n.actions);
-            }
-            mVisibility = n.visibility;
-
-            mPublicVersion = n.publicVersion;
-
-            if (n.topics != null) {
-                Collections.addAll(mTopics, n.topics);
-            }
-
-            // Extras.
-            Bundle extras = n.extras;
-            mOriginatingUserId = extras.getInt(EXTRA_ORIGINATING_USERID);
-            mContentTitle = extras.getCharSequence(EXTRA_TITLE);
-            mContentText = extras.getCharSequence(EXTRA_TEXT);
-            mSubText = extras.getCharSequence(EXTRA_SUB_TEXT);
-            mContentInfo = extras.getCharSequence(EXTRA_INFO_TEXT);
-            mProgress = extras.getInt(EXTRA_PROGRESS);
-            mProgressMax = extras.getInt(EXTRA_PROGRESS_MAX);
-            mProgressIndeterminate = extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
-            mUseChronometer = extras.getBoolean(EXTRA_SHOW_CHRONOMETER);
-            mShowWhen = extras.getBoolean(EXTRA_SHOW_WHEN);
-            if (extras.containsKey(EXTRA_LARGE_ICON)) {
-                mLargeIcon = extras.getParcelable(EXTRA_LARGE_ICON);
-            }
-            if (extras.containsKey(EXTRA_PEOPLE)) {
-                mPeople.clear();
-                Collections.addAll(mPeople, extras.getStringArray(EXTRA_PEOPLE));
-            }
         }
 
         /**
@@ -3774,38 +3506,23 @@
          * object.
          */
         public Notification build() {
-            if (mSmallIcon != null) {
-                mSmallIcon.convertToAshmem();
+            // first, add any extras from the calling code
+            if (mUserExtras != null) {
+                mN.extras = getAllExtras();
             }
-            if (mLargeIcon != null) {
-                mLargeIcon.convertToAshmem();
-            }
+
+            // lazy stuff from mContext; see comment in Builder(Context, Notification)
+            mN.extras.putParcelable(EXTRA_BUILDER_APPLICATION_INFO, mContext.getApplicationInfo());
             mOriginatingUserId = mContext.getUserId();
-            mHasThreeLines = hasThreeLines();
+            mN.extras.putInt(EXTRA_ORIGINATING_USERID, mOriginatingUserId);
 
-            Notification n = buildUnstyled();
+            buildUnstyled();
 
             if (mStyle != null) {
-                mStyle.purgeResources();
-                n = mStyle.buildStyled(n);
+                mStyle.buildStyled(mN);
             }
 
-            if (mExtras != null) {
-                n.extras.putAll(mExtras);
-            }
-
-            if (mRebuildBundle.size() > 0) {
-                n.extras.putAll(mRebuildBundle);
-                mRebuildBundle.clear();
-            }
-
-            populateExtras(n.extras);
-            if (mStyle != null) {
-                mStyle.addExtras(n.extras);
-            }
-
-            mHasThreeLines = false;
-            return n;
+            return mN;
         }
 
         /**
@@ -3901,14 +3618,15 @@
             checkBuilder();
 
             // Nasty.
-            CharSequence oldBuilderContentTitle = mBuilder.mContentTitle;
+            CharSequence oldBuilderContentTitle =
+                    mBuilder.getAllExtras().getCharSequence(EXTRA_TITLE);
             if (mBigContentTitle != null) {
                 mBuilder.setContentTitle(mBigContentTitle);
             }
 
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(layoutId);
 
-            mBuilder.mContentTitle = oldBuilderContentTitle;
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TITLE, oldBuilderContentTitle);
 
             if (mBigContentTitle != null && mBigContentTitle.equals("")) {
                 contentView.setViewVisibility(R.id.line1, View.GONE);
@@ -3919,7 +3637,7 @@
             // The last line defaults to the subtext, but can be replaced by mSummaryText
             final CharSequence overflowText =
                     mSummaryTextSet ? mSummaryText
-                                    : mBuilder.mSubText;
+                                    : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT);
             if (overflowText != null) {
                 contentView.setTextViewText(R.id.text, mBuilder.processLegacyText(overflowText));
                 contentView.setViewVisibility(R.id.overflow_divider, View.VISIBLE);
@@ -3935,6 +3653,31 @@
         }
 
         /**
+         * Construct a Style-specific RemoteViews for the final 1U notification layout.
+         * The default implementation has nothing additional to add.
+         * @hide
+         */
+        public RemoteViews makeContentView() {
+            return null;
+        }
+
+        /**
+         * Construct a Style-specific RemoteViews for the final big notification layout.
+         * @hide
+         */
+        public RemoteViews makeBigContentView() {
+            return null;
+        }
+
+        /**
+         * Construct a Style-specific RemoteViews for the final HUN layout.
+         * @hide
+         */
+        public RemoteViews makeHeadsUpContentView() {
+            return null;
+        }
+
+        /**
          * Changes the padding of the first line such that the big and small content view have the
          * same top padding.
          *
@@ -3942,12 +3685,13 @@
          */
         protected void applyTopPadding(RemoteViews contentView) {
             int topPadding = Builder.calculateTopPadding(mBuilder.mContext,
-                    mBuilder.mHasThreeLines,
+                    mBuilder.hasThreeLines(),
                     mBuilder.mContext.getResources().getConfiguration().fontScale);
             contentView.setViewPadding(R.id.line1, 0, topPadding, 0, 0);
         }
 
         /**
+         * Apply any style-specific extras to this notification before shipping it out.
          * @hide
          */
         public void addExtras(Bundle extras) {
@@ -3961,6 +3705,7 @@
         }
 
         /**
+         * Reconstruct the internal state of this Style object from extras.
          * @hide
          */
         protected void restoreFromExtras(Bundle extras) {
@@ -3978,10 +3723,7 @@
          * @hide
          */
         public Notification buildStyled(Notification wip) {
-            populateTickerView(wip);
-            populateContentView(wip);
-            populateBigContentView(wip);
-            populateHeadsUpContentView(wip);
+            addExtras(wip.extras);
             return wip;
         }
 
@@ -3990,26 +3732,6 @@
          */
         public void purgeResources() {}
 
-        // The following methods are split out so we can re-create notification partially.
-        /**
-         * @hide
-         */
-        protected void populateTickerView(Notification wip) {}
-        /**
-         * @hide
-         */
-        protected void populateContentView(Notification wip) {}
-
-        /**
-         * @hide
-         */
-        protected void populateBigContentView(Notification wip) {}
-
-        /**
-         * @hide
-         */
-        protected void populateHeadsUpContentView(Notification wip) {}
-
         /**
          * Calls {@link android.app.Notification.Builder#build()} on the Builder this Style is
          * attached to.
@@ -4115,29 +3837,33 @@
             }
         }
 
-        private RemoteViews makeBigContentView() {
-            // Replace mLargeIcon with mBigLargeIcon if mBigLargeIconSet
+        /**
+         * @hide
+         */
+        public RemoteViews makeBigContentView() {
+            // Replace mN.mLargeIcon with mBigLargeIcon if mBigLargeIconSet
             // This covers the following cases:
             //   1. mBigLargeIconSet -> mBigLargeIcon (null or non-null) applies, overrides
-            //          mLargeIcon
-            //   2. !mBigLargeIconSet -> mLargeIcon applies
+            //          mN.mLargeIcon
+            //   2. !mBigLargeIconSet -> mN.mLargeIcon applies
             Icon oldLargeIcon = null;
             if (mBigLargeIconSet) {
-                oldLargeIcon = mBuilder.mLargeIcon;
-                mBuilder.mLargeIcon = mBigLargeIcon;
+                oldLargeIcon = mBuilder.mN.mLargeIcon;
+                mBuilder.mN.mLargeIcon = mBigLargeIcon;
             }
 
             RemoteViews contentView = getStandardView(mBuilder.getBigPictureLayoutResource());
 
             if (mBigLargeIconSet) {
-                mBuilder.mLargeIcon = oldLargeIcon;
+                mBuilder.mN.mLargeIcon = oldLargeIcon;
             }
 
             contentView.setImageViewBitmap(R.id.big_picture, mPicture);
 
             applyTopPadding(contentView);
 
-            boolean twoTextLines = mBuilder.mSubText != null && mBuilder.mContentText != null;
+            boolean twoTextLines = mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT) != null
+                    && mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT) != null;
             mBuilder.addProfileBadge(contentView,
                     twoTextLines ? R.id.profile_badge_line2 : R.id.profile_badge_line3);
             return contentView;
@@ -4168,14 +3894,6 @@
             }
             mPicture = extras.getParcelable(EXTRA_PICTURE);
         }
-
-        /**
-         * @hide
-         */
-        @Override
-        public void populateBigContentView(Notification wip) {
-            mBuilder.setBuilderBigContentView(wip, makeBigContentView());
-        }
     }
 
     /**
@@ -4255,15 +3973,19 @@
             mBigText = extras.getCharSequence(EXTRA_BIG_TEXT);
         }
 
-        private RemoteViews makeBigContentView() {
+        /**
+         * @hide
+         */
+        public RemoteViews makeBigContentView() {
 
             // Nasty
-            CharSequence oldBuilderContentText = mBuilder.mContentText;
-            mBuilder.mContentText = null;
+            CharSequence oldBuilderContentText =
+                    mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
 
             RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
 
-            mBuilder.mContentText = oldBuilderContentText;
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
 
             contentView.setTextViewText(R.id.big_text, mBuilder.processLegacyText(mBigText));
             contentView.setViewVisibility(R.id.big_text, View.VISIBLE);
@@ -4282,7 +4004,8 @@
         private int calculateMaxLines() {
             int lineCount = MAX_LINES;
             boolean hasActions = mBuilder.mActions.size() > 0;
-            boolean hasSummary = (mSummaryTextSet ? mSummaryText : mBuilder.mSubText) != null;
+            boolean hasSummary = (mSummaryTextSet ? mSummaryText
+                    : mBuilder.getAllExtras().getCharSequence(EXTRA_SUB_TEXT)) != null;
             if (hasActions) {
                 lineCount -= LINES_CONSUMED_BY_ACTIONS;
             }
@@ -4291,19 +4014,11 @@
             }
 
             // If we have less top padding at the top, we can fit less lines.
-            if (!mBuilder.mHasThreeLines) {
+            if (!mBuilder.hasThreeLines()) {
                 lineCount--;
             }
             return lineCount;
         }
-
-        /**
-         * @hide
-         */
-        @Override
-        public void populateBigContentView(Notification wip) {
-            mBuilder.setBuilderBigContentView(wip, makeBigContentView());
-        }
     }
 
     /**
@@ -4384,16 +4099,18 @@
             }
         }
 
-        private RemoteViews makeBigContentView() {
+        /**
+         * @hide
+         */
+        public RemoteViews makeBigContentView() {
             // Remove the content text so line3 disappears unless you have a summary
-
             // Nasty
-            CharSequence oldBuilderContentText = mBuilder.mContentText;
-            mBuilder.mContentText = null;
+            CharSequence oldBuilderContentText = mBuilder.mN.extras.getCharSequence(EXTRA_TEXT);
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
 
             RemoteViews contentView = getStandardView(mBuilder.getInboxLayoutResource());
 
-            mBuilder.mContentText = oldBuilderContentText;
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
 
             contentView.setViewVisibility(R.id.text2, View.GONE);
 
@@ -4437,14 +4154,6 @@
 
             return contentView;
         }
-
-        /**
-         * @hide
-         */
-        @Override
-        public void populateBigContentView(Notification wip) {
-            mBuilder.setBuilderBigContentView(wip, makeBigContentView());
-        }
     }
 
     /**
@@ -4536,16 +4245,16 @@
          * @hide
          */
         @Override
-        public void populateContentView(Notification wip) {
-            mBuilder.setBuilderContentView(wip, makeMediaContentView());
+        public RemoteViews makeContentView() {
+            return makeMediaContentView();
         }
 
         /**
          * @hide
          */
         @Override
-        public void populateBigContentView(Notification wip) {
-            mBuilder.setBuilderBigContentView(wip, makeMediaBigContentView());
+        public RemoteViews makeBigContentView() {
+            return makeMediaBigContentView();
         }
 
         /** @hide */
@@ -4659,7 +4368,7 @@
                     R.color.notification_media_secondary_color);
             contentView.setTextColor(R.id.title, primaryColor);
             if (mBuilder.showsTimeOrChronometer()) {
-                if (mBuilder.mUseChronometer) {
+                if (mBuilder.getAllExtras().getBoolean(EXTRA_SHOW_CHRONOMETER)) {
                     contentView.setTextColor(R.id.chronometer, secondaryColor);
                 } else {
                     contentView.setTextColor(R.id.time, secondaryColor);
@@ -5503,7 +5212,7 @@
         /**
          * Gets the accent color.
          *
-         * @see setColor
+         * @see #setColor
          */
         @ColorInt
         public int getColor() {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index cb0ff33..07b4d39 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -207,33 +207,7 @@
      */
     public void notify(String tag, int id, Notification notification)
     {
-        int[] idOut = new int[1];
-        INotificationManager service = getService();
-        String pkg = mContext.getPackageName();
-        if (notification.sound != null) {
-            notification.sound = notification.sound.getCanonicalUri();
-            if (StrictMode.vmFileUriExposureEnabled()) {
-                notification.sound.checkFileUriExposed("Notification.sound");
-            }
-        }
-        fixLegacySmallIcon(notification, pkg);
-        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
-            if (notification.getSmallIcon() == null) {
-                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
-                    + notification);
-            }
-        }
-        if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
-        Notification stripped = notification.clone();
-        Builder.stripForDelivery(stripped);
-        try {
-            service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
-                    stripped, idOut, UserHandle.myUserId());
-            if (id != idOut[0]) {
-                Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
-            }
-        } catch (RemoteException e) {
-        }
+        notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
     }
 
     /**
@@ -251,12 +225,17 @@
             }
         }
         fixLegacySmallIcon(notification, pkg);
+        if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) {
+            if (notification.getSmallIcon() == null) {
+                throw new IllegalArgumentException("Invalid notification (no valid small icon): "
+                        + notification);
+            }
+        }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
-        Notification stripped = notification.clone();
-        Builder.stripForDelivery(stripped);
+        final Notification copy = notification.clone();
         try {
             service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
-                    stripped, idOut, user.getIdentifier());
+                    copy, idOut, user.getIdentifier());
             if (id != idOut[0]) {
                 Log.w(TAG, "notify: id corrupted: sent " + id + ", got back " + idOut[0]);
             }
@@ -287,13 +266,7 @@
      */
     public void cancel(String tag, int id)
     {
-        INotificationManager service = getService();
-        String pkg = mContext.getPackageName();
-        if (localLOGV) Log.v(TAG, pkg + ": cancel(" + id + ")");
-        try {
-            service.cancelNotificationWithTag(pkg, tag, id, UserHandle.myUserId());
-        } catch (RemoteException e) {
-        }
+        cancelAsUser(tag, id, new UserHandle(UserHandle.myUserId()));
     }
 
     /**
@@ -375,29 +348,6 @@
     /**
      * @hide
      */
-    public boolean setZenModeConfig(ZenModeConfig config, String reason) {
-        INotificationManager service = getService();
-        try {
-            return service.setZenModeConfig(config, reason);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * @hide
-     */
-    public void requestZenModeConditions(IConditionListener listener, int relevance) {
-        INotificationManager service = getService();
-        try {
-            service.requestZenModeConditions(listener, relevance);
-        } catch (RemoteException e) {
-        }
-    }
-
-    /**
-     * @hide
-     */
     public int getZenMode() {
         INotificationManager service = getService();
         try {
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 0a0d77d..4270e16 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -16,6 +16,8 @@
 
 package android.app.admin;
 
+import android.os.Bundle;
+
 import java.util.List;
 
 /**
@@ -69,4 +71,13 @@
      * @return true if the uid is an active admin with the given policy.
      */
     public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
+
+    /**
+     * Takes a {@link Bundle} containing "base" user restrictions stored in
+     * {@link com.android.server.pm.UserManagerService}, mixes restrictions set by the device owner
+     * and the profile owner and returns the merged restrictions.
+     *
+     * This method always returns a new {@link Bundle}.
+     */
+    public abstract Bundle getComposedUserRestrictions(int userId, Bundle inBundle);
 }
diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index cddf47a..39902d7 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -14,6 +14,7 @@
  */
 public class AssistContent implements Parcelable {
     private boolean mIsAppProvidedIntent = false;
+    private boolean mIsAppProvidedWebUri = false;
     private Intent mIntent;
     private String mStructuredData;
     private ClipData mClipData;
@@ -39,7 +40,7 @@
             Uri uri = intent.getData();
             if (uri != null) {
                 if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
-                    setWebUri(uri);
+                    mUri = uri;
                 }
             }
         }
@@ -116,6 +117,7 @@
      * leave the null and only report the local intent and clip data.
      */
     public void setWebUri(Uri uri) {
+        mIsAppProvidedWebUri = true;
         mUri = uri;
     }
 
@@ -128,6 +130,16 @@
     }
 
     /**
+     * Returns whether or not the current {@link #getWebUri} was explicitly provided in
+     * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not,
+     * the Intent was automatically set based on
+     * {@link android.app.Activity#getIntent Activity.getIntent}.
+     */
+    public boolean isAppProvidedWebUri() {
+        return mIsAppProvidedWebUri;
+    }
+
+    /**
      * Return Bundle for extra vendor-specific data that can be modified and examined.
      */
     public Bundle getExtras() {
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClient.java b/core/java/android/bluetooth/BluetoothHeadsetClient.java
index ff4ebee..874026f 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClient.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClient.java
@@ -1059,6 +1059,41 @@
     }
 
     /**
+     * Sets whether audio routing is allowed.
+     *
+     * Note: This is an internal function and shouldn't be exposed
+     */
+    public void setAudioRouteAllowed(boolean allowed) {
+        if (VDBG) log("setAudioRouteAllowed");
+        if (mService != null && isEnabled()) {
+            try {
+                mService.setAudioRouteAllowed(allowed);
+            } 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()));
+        }
+    }
+
+    /**
+     * Returns whether audio routing is allowed.
+     *
+     * Note: This is an internal function and shouldn't be exposed
+     */
+    public boolean getAudioRouteAllowed() {
+        if (VDBG) log("getAudioRouteAllowed");
+        if (mService != null && isEnabled()) {
+            try {
+                return mService.getAudioRouteAllowed();
+            } 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()));
+        }
+        return false;
+    }
+
+    /**
      * Initiates a connection of audio channel.
      *
      * It setup SCO channel with remote connected Handsfree AG device.
diff --git a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
index e518b7d..79ae4e4 100644
--- a/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/core/java/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -62,6 +62,8 @@
     int getAudioState(in BluetoothDevice device);
     boolean connectAudio();
     boolean disconnectAudio();
+    void setAudioRouteAllowed(boolean allowed);
+    boolean getAudioRouteAllowed();
 
     Bundle getCurrentAgFeatures(in BluetoothDevice device);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6740d43..d7e94d0 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1658,6 +1658,14 @@
             = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT";
 
     /**
+     * Boolean list describing if the app is a system app for apps that have one or more runtime
+     * permissions.
+     * @hide
+     */
+    public static final String EXTRA_GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT
+            = "android.intent.extra.GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT";
+
+    /**
      * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts.
      * @hide
      */
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 3853772..7ca39cb 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -671,6 +671,13 @@
      */
     public boolean resizeable;
 
+    /**
+     * Value indicating if the activity is supports picture-in-picture form of multi-window mode.
+     * See {@link android.R.attr#supportsPictureInPicture}.
+     * @hide
+     */
+    public boolean supportsPip;
+
     /** @hide */
     public static final int LOCK_TASK_LAUNCH_MODE_DEFAULT = 0;
     /** @hide */
@@ -723,6 +730,7 @@
         parentActivityName = orig.parentActivityName;
         maxRecents = orig.maxRecents;
         resizeable = orig.resizeable;
+        supportsPip = orig.supportsPip;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
         layout = orig.layout;
     }
@@ -769,8 +777,8 @@
         if (uiOptions != 0) {
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
-        pw.println(prefix + "resizeable=" + resizeable + " lockTaskLaunchMode="
-                + lockTaskLaunchModeToString(lockTaskLaunchMode));
+        pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
+        pw.println(prefix + "lockTaskLaunchMode=" + lockTaskLaunchModeToString(lockTaskLaunchMode));
         if (layout != null) {
             pw.println(prefix + "initialLayout=" + layout.width + "|"
                     + layout.widthFraction + ", " + layout.height + "|"
@@ -806,6 +814,7 @@
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
         dest.writeInt(resizeable ? 1 : 0);
+        dest.writeInt(supportsPip ? 1 : 0);
         dest.writeInt(lockTaskLaunchMode);
         if (layout != null) {
             dest.writeInt(1);
@@ -847,6 +856,7 @@
         persistableMode = source.readInt();
         maxRecents = source.readInt();
         resizeable = (source.readInt() == 1);
+        supportsPip = (source.readInt() == 1);
         lockTaskLaunchMode = source.readInt();
         if (source.readInt() == 1) {
             layout = new Layout(source);
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
index 56b3173..a5a8e3f 100644
--- a/core/java/android/content/pm/AppsQueryHelper.java
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -23,6 +23,8 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -46,6 +48,14 @@
      */
     public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;
 
+    /**
+     * Return all input methods that are marked as default.
+     * <p>When this flag is set, {@code user} specified in
+     * {@link #queryApps(int, boolean, UserHandle)} must be
+     * {@link UserHandle#myUserId user of the current process}.
+     */
+    public static int GET_DEFAULT_IMES = 1 << 2;
+
     private final Context mContext;
     private List<ApplicationInfo> mAllApps;
 
@@ -56,13 +66,14 @@
     /**
      * Return a List of all packages that satisfy a specified criteria.
      * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
-     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM}
+     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM} or {@link #GET_DEFAULT_IMES}.
      * @param systemAppsOnly if true, only system apps will be returned
      * @param user user, whose apps are queried
      */
     public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
         boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
         boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
+        boolean defaultImes = (flags & GET_DEFAULT_IMES) > 0;
         if (mAllApps == null) {
             mAllApps = getAllApps(user.getIdentifier());
         }
@@ -118,6 +129,33 @@
             }
         }
 
+        if (defaultImes) {
+            if (UserHandle.myUserId() != user.getIdentifier()) {
+                throw new IllegalArgumentException("Specified user handle " + user
+                        + " is not a user of the current process.");
+            }
+            List<InputMethodInfo> imis = getInputMethodList();
+            int imisSize = imis.size();
+            ArraySet<String> defaultImePackages = new ArraySet<>();
+            for (int i = 0; i < imisSize; i++) {
+                InputMethodInfo imi = imis.get(i);
+                if (imi.isDefault(mContext)) {
+                    defaultImePackages.add(imi.getPackageName());
+                }
+            }
+            final int allAppsSize = mAllApps.size();
+            for (int i = 0; i < allAppsSize; i++) {
+                final ApplicationInfo appInfo = mAllApps.get(i);
+                if (systemAppsOnly && !appInfo.isSystemApp()) {
+                    continue;
+                }
+                final String packageName = appInfo.packageName;
+                if (defaultImePackages.contains(packageName)) {
+                    result.add(packageName);
+                }
+            }
+        }
+
         return result;
     }
 
@@ -150,4 +188,12 @@
             throw new IllegalStateException("Package manager has died", e);
         }
     }
+
+    @VisibleForTesting
+    @SuppressWarnings("unchecked")
+    protected List<InputMethodInfo> getInputMethodList() {
+        InputMethodManager imm = (InputMethodManager)
+                mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
+        return imm.getInputMethodList();
+    }
 }
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index a5e9faf..fec2c44 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -63,7 +63,9 @@
     boolean isPackageAvailable(String packageName, int userId);
     PackageInfo getPackageInfo(String packageName, int flags, int userId);
     int getPackageUid(String packageName, int userId);
+    int getPackageUidEtc(String packageName, int flags, int userId);
     int[] getPackageGids(String packageName, int userId);
+    int[] getPackageGidsEtc(String packageName, int flags, int userId);
 
     String[] currentToCanonicalPackageNames(in String[] names);
     String[] canonicalToCurrentPackageNames(in String[] names);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index aed1a0b..27ecf9f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1708,6 +1708,15 @@
     public static final String FEATURE_BACKUP = "android.software.backup";
 
     /**
+     * Feature for {@link #getSystemAvailableFeatures} and
+     * {@link #hasSystemFeature}: The device supports freeform window management.
+     * Windows have title bars and can be moved and resized.
+     */
+    @SdkConstant(SdkConstantType.FEATURE)
+    public static final String FEATURE_FREEFORM_WINDOW_MANAGEMENT
+            = "android.software.freeform_window_management";
+
+    /**
      * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
      * The device supports creating secondary users and managed profiles via
      * {@link DevicePolicyManager}.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 1e85dfb..5d73b06 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3220,6 +3220,9 @@
                     R.styleable.AndroidManifestActivity_resizeableActivity,
                     owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N);
 
+            a.info.supportsPip = a.info.resizeable ? sa.getBoolean(
+                    R.styleable.AndroidManifestActivity_supportsPictureInPicture, false) : false;
+
             a.info.screenOrientation = sa.getInt(
                     R.styleable.AndroidManifestActivity_screenOrientation,
                     ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 1fcfaca..51796eb 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -513,7 +513,7 @@
      * {@link CameraManager#registerAvailabilityCallback} to be notified of such availability
      * changes.</p>
      *
-     * @see registerAvailabilityCallback
+     * @see #registerAvailabilityCallback
      */
     public static abstract class AvailabilityCallback {
 
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 6bfa2a4..1bb0fbb 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -119,8 +119,12 @@
             //
             // For one such example of this, see b/18867306.
             //
-            // TODO: Remove this special case altogether.
-            if (before.isIPv4Provisioned() && !after.isIPv4Provisioned()) {
+            // Additionally, losing IPv6 provisioning can result in TCP
+            // connections getting stuck until timeouts fire and other
+            // baffling failures. Therefore, loss of either IPv4 or IPv6 on a
+            // previously dualstack network is deemed a lost of provisioning.
+            if ((before.isIPv4Provisioned() && !after.isIPv4Provisioned()) ||
+                (before.isIPv6Provisioned() && !after.isIPv6Provisioned())) {
                 return ProvisioningChange.LOST_PROVISIONING;
             }
             return ProvisioningChange.STILL_PROVISIONED;
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 3ade170..12cac85 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -55,14 +55,12 @@
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
     boolean hasUserRestriction(in String restrictionKey, int userHandle);
-    void setUserRestrictions(in Bundle restrictions, int userHandle);
     void setUserRestriction(String key, boolean value, int userId);
     void setSystemControlledUserRestriction(String key, boolean value, int userId);
     void setApplicationRestrictions(in String packageName, in Bundle restrictions,
             int userHandle);
     Bundle getApplicationRestrictions(in String packageName);
     Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
-    void removeRestrictions();
     void setDefaultGuestRestrictions(in Bundle restrictions);
     Bundle getDefaultGuestRestrictions();
     boolean markGuestForDeletion(int userHandle);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 1273772b..5852f5f 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.IntegerRes;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -42,6 +43,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import dalvik.system.VMRuntime;
+
 /**
  * Container for a message (data and object references) that can
  * be sent through an IBinder.  A Parcel can contain both flattened data
@@ -193,6 +196,7 @@
      * indicating that we're responsible for its lifecycle.
      */
     private boolean mOwnsNativeParcelObject;
+    private long mNativeSize;
 
     private RuntimeException mStack;
 
@@ -244,7 +248,7 @@
     private static native int nativeDataAvail(long nativePtr);
     private static native int nativeDataPosition(long nativePtr);
     private static native int nativeDataCapacity(long nativePtr);
-    private static native void nativeSetDataSize(long nativePtr, int size);
+    private static native long nativeSetDataSize(long nativePtr, int size);
     private static native void nativeSetDataPosition(long nativePtr, int pos);
     private static native void nativeSetDataCapacity(long nativePtr, int size);
 
@@ -259,7 +263,7 @@
     private static native void nativeWriteDouble(long nativePtr, double val);
     private static native void nativeWriteString(long nativePtr, String val);
     private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
-    private static native void nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
+    private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
 
     private static native byte[] nativeCreateByteArray(long nativePtr);
     private static native byte[] nativeReadBlob(long nativePtr);
@@ -272,13 +276,13 @@
     private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
 
     private static native long nativeCreate();
-    private static native void nativeFreeBuffer(long nativePtr);
+    private static native long nativeFreeBuffer(long nativePtr);
     private static native void nativeDestroy(long nativePtr);
 
     private static native byte[] nativeMarshall(long nativePtr);
-    private static native void nativeUnmarshall(
+    private static native long nativeUnmarshall(
             long nativePtr, byte[] data, int offset, int length);
-    private static native void nativeAppendFrom(
+    private static native long nativeAppendFrom(
             long thisNativePtr, long otherNativePtr, int offset, int length);
     private static native boolean nativeHasFileDescriptors(long nativePtr);
     private static native void nativeWriteInterfaceToken(long nativePtr, String interfaceName);
@@ -390,7 +394,7 @@
      * @param size The new number of bytes in the Parcel.
      */
     public final void setDataSize(int size) {
-        nativeSetDataSize(mNativePtr, size);
+        updateNativeSize(nativeSetDataSize(mNativePtr, size));
     }
 
     /**
@@ -442,11 +446,11 @@
      * Set the bytes in data to be the raw bytes of this Parcel.
      */
     public final void unmarshall(byte[] data, int offset, int length) {
-        nativeUnmarshall(mNativePtr, data, offset, length);
+        updateNativeSize(nativeUnmarshall(mNativePtr, data, offset, length));
     }
 
     public final void appendFrom(Parcel parcel, int offset, int length) {
-        nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length);
+        updateNativeSize(nativeAppendFrom(mNativePtr, parcel.mNativePtr, offset, length));
     }
 
     /**
@@ -599,7 +603,24 @@
      * if {@link Parcelable#PARCELABLE_WRITE_RETURN_VALUE} is set.</p>
      */
     public final void writeFileDescriptor(FileDescriptor val) {
-        nativeWriteFileDescriptor(mNativePtr, val);
+        updateNativeSize(nativeWriteFileDescriptor(mNativePtr, val));
+    }
+
+    private void updateNativeSize(long newNativeSize) {
+        if (mOwnsNativeParcelObject) {
+            if (newNativeSize > Integer.MAX_VALUE) {
+                newNativeSize = Integer.MAX_VALUE;
+            }
+            if (newNativeSize != mNativeSize) {
+                int delta = (int) (newNativeSize - mNativeSize);
+                if (delta > 0) {
+                    VMRuntime.getRuntime().registerNativeAllocation(delta);
+                } else {
+                    VMRuntime.getRuntime().registerNativeFree(-delta);
+                }
+                mNativeSize = newNativeSize;
+            }
+        }
     }
 
     /**
@@ -2545,7 +2566,7 @@
 
     private void freeBuffer() {
         if (mOwnsNativeParcelObject) {
-            nativeFreeBuffer(mNativePtr);
+            updateNativeSize(nativeFreeBuffer(mNativePtr));
         }
     }
 
@@ -2553,6 +2574,7 @@
         if (mNativePtr != 0) {
             if (mOwnsNativeParcelObject) {
                 nativeDestroy(mNativePtr);
+                updateNativeSize(0);
             }
             mNativePtr = 0;
         }
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index d64273a..73c2c80 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -44,7 +44,7 @@
     private FastPrintWriter mOutPrintWriter;
     private FastPrintWriter mErrPrintWriter;
 
-    public void exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
+    public int exec(Binder target, FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ResultReceiver resultReceiver) {
         mTarget = target;
         mIn = in;
@@ -89,6 +89,7 @@
             mResultReceiver.send(res, null);
         }
         if (DEBUG) Slog.d(TAG, "Finished command " + mCmd + " on " + mTarget);
+        return res;
     }
 
     public PrintWriter getOutPrintWriter() {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1c1575e..2e31ab6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -21,6 +21,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
@@ -55,7 +56,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts";
@@ -67,7 +69,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi";
@@ -78,7 +81,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_INSTALL_APPS = "no_install_apps";
@@ -89,7 +93,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
@@ -102,7 +107,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_SHARE_LOCATION = "no_share_location";
@@ -114,7 +120,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
@@ -127,7 +134,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth";
@@ -139,7 +147,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
@@ -150,7 +159,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials";
@@ -163,7 +173,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_REMOVE_USER = "no_remove_user";
@@ -174,7 +185,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features";
@@ -187,7 +199,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_VPN = "no_config_vpn";
@@ -199,7 +212,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering";
@@ -213,7 +227,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_NETWORK_RESET = "no_network_reset";
@@ -227,7 +242,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_FACTORY_RESET = "no_factory_reset";
@@ -241,7 +257,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_ADD_USER = "no_add_user";
@@ -252,7 +269,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps";
@@ -266,7 +284,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts";
@@ -280,7 +299,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks";
@@ -300,7 +320,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_APPS_CONTROL = "no_control_apps";
@@ -312,7 +333,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media";
@@ -324,7 +346,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
@@ -336,7 +359,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
@@ -350,7 +374,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls";
@@ -361,7 +386,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_SMS = "no_sms";
@@ -373,7 +399,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_FUN = "no_fun";
@@ -393,7 +420,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows";
@@ -406,7 +434,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste";
@@ -417,7 +446,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam";
@@ -426,7 +456,8 @@
      * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
      * is always set for managed profiles.
      * @hide
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_WALLPAPER = "no_wallpaper";
@@ -438,7 +469,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String DISALLOW_SAFE_BOOT = "no_safe_boot";
@@ -447,7 +479,8 @@
      * Specifies if a user is not allowed to record audio. This restriction is always enabled for
      * background users. The default value is <code>false</code>.
      *
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      * @hide
      */
@@ -466,7 +499,8 @@
      *
      * <p/>Key for user restrictions.
      * <p/>Type: Boolean
-     * @see #setUserRestrictions(Bundle)
+     * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+     * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
      * @see #getUserRestrictions()
      */
     public static final String ALLOW_PARENT_PROFILE_APP_LINKING
@@ -499,14 +533,9 @@
     /** @hide */
     public static final int PIN_VERIFICATION_SUCCESS = -1;
 
-    private static UserManager sInstance = null;
-
     /** @hide */
-    public synchronized static UserManager get(Context context) {
-        if (sInstance == null) {
-            sInstance = (UserManager) context.getSystemService(Context.USER_SERVICE);
-        }
-        return sInstance;
+    public static UserManager get(Context context) {
+        return (UserManager) context.getSystemService(Context.USER_SERVICE);
     }
 
     /** @hide */
@@ -740,36 +769,23 @@
     }
 
     /**
-     * Sets all the user-wide restrictions for this user.
-     * Requires the MANAGE_USERS permission.
-     * @param restrictions the Bundle containing all the restrictions.
-     * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
-     * android.content.ComponentName, String)} or
-     * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
-     * android.content.ComponentName, String)} instead.
+     * This will no longer work.  Device owners and profile owners should use
+     * {@link DevicePolicyManager#addUserRestriction(ComponentName, String)} instead.
      */
+    // System apps should use UserManager.setUserRestriction() instead.
     @Deprecated
     public void setUserRestrictions(Bundle restrictions) {
-        setUserRestrictions(restrictions, Process.myUserHandle());
+        throw new UnsupportedOperationException("This method is no longer supported");
     }
 
     /**
-     * Sets all the user-wide restrictions for the specified user.
-     * Requires the MANAGE_USERS permission.
-     * @param restrictions the Bundle containing all the restrictions.
-     * @param userHandle the UserHandle of the user for whom to set the restrictions.
-     * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
-     * android.content.ComponentName, String)} or
-     * {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
-     * android.content.ComponentName, String)} instead.
+     * This will no longer work.  Device owners and profile owners should use
+     * {@link DevicePolicyManager#addUserRestriction(ComponentName, String)} instead.
      */
+    // System apps should use UserManager.setUserRestriction() instead.
     @Deprecated
     public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
-        try {
-            mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not set user restrictions", re);
-        }
+        throw new UnsupportedOperationException("This method is no longer supported");
     }
 
     /**
@@ -784,9 +800,7 @@
      */
     @Deprecated
     public void setUserRestriction(String key, boolean value) {
-        Bundle bundle = getUserRestrictions();
-        bundle.putBoolean(key, value);
-        setUserRestrictions(bundle);
+        setUserRestriction(key, value, Process.myUserHandle());
     }
 
     /**
@@ -882,9 +896,8 @@
         try {
             user = mService.createUser(name, flags);
             if (user != null && !user.isAdmin()) {
-                Bundle userRestrictions = mService.getUserRestrictions(user.id);
-                addDefaultUserRestrictions(userRestrictions);
-                mService.setUserRestrictions(userRestrictions, user.id);
+                mService.setUserRestriction(DISALLOW_SMS, true, user.id);
+                mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
             }
         } catch (RemoteException re) {
             Log.w(TAG, "Could not create a user", re);
@@ -899,27 +912,22 @@
      * @hide
      */
     public UserInfo createGuest(Context context, String name) {
-        UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
-        if (guest != null) {
-            Settings.Secure.putStringForUser(context.getContentResolver(),
-                    Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
-            try {
-                Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
-                guestRestrictions.putBoolean(DISALLOW_SMS, true);
-                guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
-                mService.setUserRestrictions(guestRestrictions, guest.id);
-            } catch (RemoteException re) {
-                Log.w(TAG, "Could not update guest restrictions");
+        UserInfo guest = null;
+        try {
+            guest = mService.createUser(name, UserInfo.FLAG_GUEST);
+            if (guest != null) {
+                Settings.Secure.putStringForUser(context.getContentResolver(),
+                        Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
+
+                mService.setUserRestriction(DISALLOW_SMS, true, guest.id);
+                mService.setUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES, true, guest.id);
             }
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not create a user", re);
         }
         return guest;
     }
 
-    private static void addDefaultUserRestrictions(Bundle restrictions) {
-        restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true);
-        restrictions.putBoolean(DISALLOW_SMS, true);
-    }
-
     /**
      * Creates a user with the specified name and options as a profile of another user.
      * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
@@ -1465,15 +1473,6 @@
         return false;
     }
 
-    /** @hide */
-    public void removeRestrictions() {
-        try {
-            mService.removeRestrictions();
-        } catch (RemoteException re) {
-            Log.w(TAG, "Could not change restrictions pin");
-        }
-    }
-
     /**
      * @hide
      * Set restrictions that should apply to any future guest user that's created.
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
new file mode 100644
index 0000000..d7be6d8
--- /dev/null
+++ b/core/java/android/os/UserManagerInternal.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+/**
+ * @hide Only for use within the system server.
+ */
+public abstract class UserManagerInternal {
+    /**
+     * Lock that must be held when calling certain methods in this class.
+     *
+     * This is used to avoid dead lock between
+     * {@link com.android.server.pm.UserManagerService} and
+     * {@link com.android.server.devicepolicy.DevicePolicyManagerService}.  This lock should not
+     * be newly taken while holding the DPMS lock, which would cause a dead lock.  Take this
+     * lock first before taking the DPMS lock to avoid that.
+     */
+    public abstract Object getUserRestrictionsLock();
+
+    /**
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get
+     * {@link com.android.server.pm.UserManagerService} to update effective user restrictions.
+     *
+     * Must be called while taking the {@link #getUserRestrictionsLock()} lock.
+     */
+    public abstract void updateEffectiveUserRestrictionsRL(int userId);
+
+    /**
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get
+     * {@link com.android.server.pm.UserManagerService} to update effective user restrictions.
+     *
+     * Must be called while taking the {@link #getUserRestrictionsLock()} lock.
+     */
+    public abstract void updateEffectiveUserRestrictionsForAllUsersRL();
+
+    /**
+     * Returns the "base" user restrictions.
+     *
+     * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
+     * from MNC.
+     */
+    public abstract Bundle getBaseUserRestrictions(int userId);
+
+    /**
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
+     * from MNC.
+     */
+    public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId,
+            Bundle baseRestrictions);
+}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 342f8c7..4b63c36 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -38,7 +38,6 @@
 import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
-import android.util.Log;
 
 import com.android.internal.telephony.CallerInfo;
 import com.android.internal.telephony.PhoneConstants;
@@ -406,6 +405,14 @@
         public static final String SUB_ID = "sub_id";
 
         /**
+         * The post-dial portion of a dialed number, including any digits dialed after a
+         * {@link TelecomManager#DTMF_CHARACTER_PAUSE} or a {@link
+         * TelecomManager#DTMF_CHARACTER_WAIT} and these characters themselves.
+         * <P>Type: TEXT</P>
+         */
+        public static final String POST_DIAL_DIGITS = "post_dial_digits";
+
+        /**
          * If a successful call is made that is longer than this duration, update the phone number
          * in the ContactsProvider with the normalized version of the number, based on the user's
          * current country code.
@@ -436,7 +443,7 @@
         public static Uri addCall(CallerInfo ci, Context context, String number,
                 int presentation, int callType, int features, PhoneAccountHandle accountHandle,
                 long start, int duration, Long dataUsage) {
-            return addCall(ci, context, number, presentation, callType, features, accountHandle,
+            return addCall(ci, context, number, "", presentation, callType, features, accountHandle,
                     start, duration, dataUsage, false, false);
         }
 
@@ -466,10 +473,11 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
-                                  int presentation, int callType, int features, PhoneAccountHandle accountHandle,
-                                  long start, int duration, Long dataUsage, boolean addForAllUsers) {
-            return addCall(ci, context, number, presentation, callType, features, accountHandle,
-                    start, duration, dataUsage, addForAllUsers, false);
+                String postDialDigits, int presentation, int callType, int features,
+                PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
+                boolean addForAllUsers) {
+            return addCall(ci, context, number, postDialDigits, presentation, callType, features,
+                    accountHandle, start, duration, dataUsage, addForAllUsers, false);
         }
 
         /**
@@ -479,6 +487,8 @@
          * if the contact is unknown.
          * @param context the context used to get the ContentResolver
          * @param number the phone number to be added to the calls db
+         * @param postDialDigits the post-dial digits that were dialed after the number,
+         *        if it was outgoing. Otherwise it is ''.
          * @param presentation enum value from PhoneConstants.PRESENTATION_xxx, which
          *        is set by the network and denotes the number presenting rules for
          *        "allowed", "payphone", "restricted" or "unknown"
@@ -499,8 +509,9 @@
          * {@hide}
          */
         public static Uri addCall(CallerInfo ci, Context context, String number,
-                int presentation, int callType, int features, PhoneAccountHandle accountHandle,
-                long start, int duration, Long dataUsage, boolean addForAllUsers, boolean is_read) {
+                String postDialDigits, int presentation, int callType, int features,
+                PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage,
+                boolean addForAllUsers, boolean is_read) {
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
 
@@ -551,6 +562,7 @@
             ContentValues values = new ContentValues(6);
 
             values.put(NUMBER, number);
+            values.put(POST_DIAL_DIGITS, postDialDigits);
             values.put(NUMBER_PRESENTATION, Integer.valueOf(numberPresentation));
             values.put(TYPE, Integer.valueOf(callType));
             values.put(FEATURES, features);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 11effd0..ad46c3d 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5604,11 +5604,6 @@
         public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES =
                 "enabled_notification_policy_access_packages";
 
-        /**
-         * @hide
-         */
-        public static final String ENABLED_CONDITION_PROVIDERS = "enabled_condition_providers";
-
         /** @hide */
         public static final String BAR_SERVICE_COMPONENT = "bar_service_component";
 
@@ -6277,6 +6272,15 @@
         */
        public static final String FORCE_ALLOW_ON_EXTERNAL = "force_allow_on_external";
 
+        /**
+         * Whether any activity can be resized. When this is true, any
+         * activity, regardless of manifest values, can be resized for multi-window.
+         * (0 = false, 1 = true)
+         * @hide
+         */
+        public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
+                = "force_resizable_activities";
+
        /**
         * Whether user has enabled development settings.
         */
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index c679eda..bbac023 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -35,7 +35,8 @@
  * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
  * and include an intent filter with the {@link #SERVICE_INTERFACE} action. If you want users to be
  * able to create and update conditions for this service to monitor, include the
- * {@link #META_DATA_RULE_TYPE} and {@link #META_DATA_CONFIGURATION_ACTIVITY} tags. For example:</p>
+ * {@link #META_DATA_RULE_TYPE} and {@link #META_DATA_CONFIGURATION_ACTIVITY} tags and request the
+ * {@link android.Manifest.permission#ACCESS_NOTIFICATION_POLICY} permission. For example:</p>
  * <pre>
  * &lt;service android:name=".MyConditionProvider"
  *          android:label="&#64;string/service_name"
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d424546..7e7b5fc 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -31,6 +31,7 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.graphics.Bitmap;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcel;
@@ -472,9 +473,10 @@
                 StatusBarNotification sbn = list.get(i);
                 Notification notification = sbn.getNotification();
                 try {
-                    Builder.rebuild(getContext(), notification);
                     // convert icon metadata to legacy format for older clients
                     createLegacyIconExtras(notification);
+                    // populate remote views for older clients.
+                    maybePopulateRemoteViews(notification);
                 } catch (IllegalArgumentException e) {
                     if (corruptNotifications == null) {
                         corruptNotifications = new ArrayList<>(N);
@@ -676,6 +678,18 @@
         }
     }
 
+    /**
+     * Populates remote views for pre-N targeting apps.
+     */
+    private void maybePopulateRemoteViews(Notification notification) {
+        if (getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+            Builder builder = Builder.recoverBuilder(getContext(), notification);
+            notification.contentView = builder.makeContentView();
+            notification.bigContentView = builder.makeBigContentView();
+            notification.headsUpContentView = builder.makeHeadsUpContentView();
+        }
+    }
+
     private class INotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
@@ -689,9 +703,10 @@
             }
 
             try {
-                Notification.Builder.rebuild(getContext(), sbn.getNotification());
+                Notification notification = sbn.getNotification();
                 // convert icon metadata to legacy format for older clients
                 createLegacyIconExtras(sbn.getNotification());
+                maybePopulateRemoteViews(sbn.getNotification());
             } catch (IllegalArgumentException e) {
                 // drop corrupt notification
                 sbn = null;
diff --git a/core/java/android/text/method/ArrowKeyMovementMethod.java b/core/java/android/text/method/ArrowKeyMovementMethod.java
index de509b2..2459cfa 100644
--- a/core/java/android/text/method/ArrowKeyMovementMethod.java
+++ b/core/java/android/text/method/ArrowKeyMovementMethod.java
@@ -238,6 +238,7 @@
             initialScrollY = Touch.getInitialScrollY(widget, buffer);
         }
 
+        boolean wasTouchSelecting = isTouchSelecting(isMouse, buffer);
         boolean handled = Touch.onTouchEvent(widget, buffer, event);
 
         if (widget.didTouchFocusSelect() && !isMouse) {
@@ -267,9 +268,9 @@
                 // Cursor can be active at any location in the text while mouse pointer can start
                 // selection from a totally different location. Use LAST_TAP_DOWN span to ensure
                 // text selection will start from mouse pointer location.
+                final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
                 if (isMouse && Touch.isSelectionStarted(buffer)) {
-                    int offset = buffer.getSpanStart(LAST_TAP_DOWN);
-                    Selection.setSelection(buffer, offset);
+                    Selection.setSelection(buffer, startOffset);
                 }
 
                 if (isTouchSelecting(isMouse, buffer) && handled) {
@@ -284,9 +285,9 @@
                     // Update selection as we're moving the selection area.
 
                     // Get the current touch position
-                    int offset = widget.getOffsetForPosition(event.getX(), event.getY());
-
-                    Selection.extendSelection(buffer, offset);
+                    final int offset = widget.getOffsetForPosition(event.getX(), event.getY());
+                    Selection.setSelection(buffer, Math.min(startOffset, offset),
+                            Math.max(startOffset, offset));
                     return true;
                 }
             } else if (action == MotionEvent.ACTION_UP) {
@@ -300,10 +301,12 @@
                     return true;
                 }
 
-                int offset = widget.getOffsetForPosition(event.getX(), event.getY());
-                if (isTouchSelecting(isMouse, buffer)) {
+                if (wasTouchSelecting) {
+                    final int startOffset = buffer.getSpanStart(LAST_TAP_DOWN);
+                    final int endOffset = widget.getOffsetForPosition(event.getX(), event.getY());
+                    Selection.setSelection(buffer, Math.min(startOffset, endOffset),
+                            Math.max(startOffset, endOffset));
                     buffer.removeSpan(LAST_TAP_DOWN);
-                    Selection.extendSelection(buffer, offset);
                 }
 
                 MetaKeyKeyListener.adjustMetaAfterKeypress(buffer);
diff --git a/core/java/android/util/SparseIntArray.java b/core/java/android/util/SparseIntArray.java
index e5c729d..3b832dd 100644
--- a/core/java/android/util/SparseIntArray.java
+++ b/core/java/android/util/SparseIntArray.java
@@ -19,6 +19,8 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 
+import java.util.Arrays;
+
 import libcore.util.EmptyArray;
 
 /**
@@ -239,6 +241,18 @@
     }
 
     /**
+     * Provides a copy of keys.
+     *
+     * @hide
+     * */
+    public int[] copyKeys() {
+        if (size() == 0) {
+            return null;
+        }
+        return Arrays.copyOf(mKeys, size());
+    }
+
+    /**
      * {@inheritDoc}
      *
      * <p>This implementation composes a string by iterating over its mappings.
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index c1eb80d..37d6757 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -343,15 +343,15 @@
         int seconds = (int) Math.floor(duration / 1000);
         int days = 0, hours = 0, minutes = 0;
 
-        if (seconds > SECONDS_PER_DAY) {
+        if (seconds >= SECONDS_PER_DAY) {
             days = seconds / SECONDS_PER_DAY;
             seconds -= days * SECONDS_PER_DAY;
         }
-        if (seconds > SECONDS_PER_HOUR) {
+        if (seconds >= SECONDS_PER_HOUR) {
             hours = seconds / SECONDS_PER_HOUR;
             seconds -= hours * SECONDS_PER_HOUR;
         }
-        if (seconds > SECONDS_PER_MINUTE) {
+        if (seconds >= SECONDS_PER_MINUTE) {
             minutes = seconds / SECONDS_PER_MINUTE;
             seconds -= minutes * SECONDS_PER_MINUTE;
         }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7adfa8d..f18b35d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -138,7 +138,7 @@
      * @hide
      */
     void overridePendingAppTransitionMultiThumb(in AppTransitionAnimationSpec[] specs,
-            IRemoteCallback startedCallback, boolean scaleUp);
+            IRemoteCallback startedCallback, IRemoteCallback finishedCallback, boolean scaleUp);
     void overridePendingAppTransitionInPlace(String packageName, int anim);
     void executeAppTransition();
     void setAppStartingWindow(IBinder token, String pkg, int theme,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fa86c74..8b804e8 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2415,6 +2415,7 @@
      *                     1             PFLAG3_SCROLL_INDICATOR_START
      *                    1              PFLAG3_SCROLL_INDICATOR_END
      *                   1               PFLAG3_ASSIST_BLOCKED
+     *            1111111                PFLAG3_POINTER_ICON_MASK
      * |-------|-------|-------|-------|
      */
 
@@ -2611,6 +2612,36 @@
     static final int PFLAG3_ASSIST_BLOCKED = 0x4000;
 
     /**
+     * The mask for use with private flags indicating bits used for pointer icon shapes.
+     */
+    static final int PFLAG3_POINTER_ICON_MASK = 0x7f8000;
+
+    /**
+     * Left-shift used for pointer icon shape values in private flags.
+     */
+    static final int PFLAG3_POINTER_ICON_LSHIFT = 15;
+
+    /**
+     * Value indicating {@link PointerIcon.STYLE_NOT_SPECIFIED}.
+     */
+    private static final int PFLAG3_POINTER_ICON_NOT_SPECIFIED = 0 << PFLAG3_POINTER_ICON_LSHIFT;
+
+    /**
+     * Value indicating {@link PointerIcon.STYLE_NULL}.
+     */
+    private static final int PFLAG3_POINTER_ICON_NULL = 1 << PFLAG3_POINTER_ICON_LSHIFT;
+
+    /**
+     * Value incicating {@link PointerIcon.STYLE_CUSTOM}.
+     */
+    private static final int PFLAG3_POINTER_ICON_CUSTOM = 2 << PFLAG3_POINTER_ICON_LSHIFT;
+
+    /**
+     * The base value for other pointer icon shapes.
+     */
+    private static final int PFLAG3_POINTER_ICON_VALUE_START = 3 << PFLAG3_POINTER_ICON_LSHIFT;
+
+    /**
      * Always allow a user to over-scroll this view, provided it is a
      * view that can scroll.
      *
@@ -5341,21 +5372,53 @@
     }
 
     /**
-     * Call this view's OnLongClickListener, if it is defined. Invokes the context menu if the
-     * OnLongClickListener did not consume the event.
+     * Calls this view's OnLongClickListener, if it is defined. Invokes the
+     * context menu if the OnLongClickListener did not consume the event.
      *
-     * @return True if one of the above receivers consumed the event, false otherwise.
+     * @return {@code true} if one of the above receivers consumed the event,
+     *         {@code false} otherwise
      */
     public boolean performLongClick() {
+        return performLongClickInternal(false, 0, 0);
+    }
+
+    /**
+     * Calls this view's OnLongClickListener, if it is defined. Invokes the
+     * context menu if the OnLongClickListener did not consume the event,
+     * anchoring it to an (x,y) coordinate.
+     *
+     * @param x x coordinate of the anchoring touch event
+     * @param y y coordinate of the anchoring touch event
+     * @return {@code true} if one of the above receivers consumed the event,
+     *         {@code false} otherwise
+     */
+    public boolean performLongClick(float x, float y) {
+        return performLongClickInternal(true, x, y);
+    }
+
+    /**
+     * Calls this view's OnLongClickListener, if it is defined. Invokes the
+     * context menu if the OnLongClickListener did not consume the event,
+     * optionally anchoring it to an (x,y) coordinate.
+     *
+     * @param isAnchored whether this long click is anchored to a touch event
+     * @param x x coordinate of the anchoring touch event, ignored if
+     *          {@code isAnchored} is set to {@code false}
+     * @param y y coordinate of the anchoring touch event, ignored if
+     *          {@code isAnchored} is set to {@code false}
+     * @return {@code true} if one of the above receivers consumed the event,
+     *         {@code false} otherwise
+     */
+    private boolean performLongClickInternal(boolean isAnchored, float x, float y) {
         sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
 
         boolean handled = false;
-        ListenerInfo li = mListenerInfo;
+        final ListenerInfo li = mListenerInfo;
         if (li != null && li.mOnLongClickListener != null) {
             handled = li.mOnLongClickListener.onLongClick(View.this);
         }
         if (!handled) {
-            handled = showContextMenu();
+            handled = isAnchored ? showContextMenu(x, y) : showContextMenu();
         }
         if (handled) {
             performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -10002,32 +10065,36 @@
      * KeyEvent.Callback.onKeyDown()}: perform press of the view
      * when {@link KeyEvent#KEYCODE_DPAD_CENTER} or {@link KeyEvent#KEYCODE_ENTER}
      * is released, if the view is enabled and clickable.
+     * <p>
+     * Key presses in software keyboards will generally NOT trigger this
+     * listener, although some may elect to do so in some situations. Do not
+     * rely on this to catch software key presses.
      *
-     * <p>Key presses in software keyboards will generally NOT trigger this listener,
-     * although some may elect to do so in some situations. Do not rely on this to
-     * catch software key presses.
-     *
-     * @param keyCode A key code that represents the button pressed, from
-     *                {@link android.view.KeyEvent}.
-     * @param event   The KeyEvent object that defines the button action.
+     * @param keyCode a key code that represents the button pressed, from
+     *                {@link android.view.KeyEvent}
+     * @param event the KeyEvent object that defines the button action
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-        boolean result = false;
-
         if (KeyEvent.isConfirmKey(keyCode)) {
             if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                 return true;
             }
-            // Long clickable items don't necessarily have to be clickable
-            if (((mViewFlags & CLICKABLE) == CLICKABLE ||
-                    (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) &&
-                    (event.getRepeatCount() == 0)) {
-                setPressed(true);
-                checkForLongClick(0);
+
+            // Long clickable items don't necessarily have to be clickable.
+            if (((mViewFlags & CLICKABLE) == CLICKABLE
+                    || (mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
+                    && (event.getRepeatCount() == 0)) {
+                // For the purposes of menu anchoring and drawable hotspots,
+                // key events are considered to be at the center of the view.
+                final float x = getWidth() / 2f;
+                final float y = getHeight() / 2f;
+                setPressed(true, x, y);
+                checkForLongClick(0, x, y);
                 return true;
             }
         }
-        return result;
+
+        return false;
     }
 
     /**
@@ -10555,7 +10622,7 @@
                     } else {
                         // Not inside a scrolling container, so show the feedback right away
                         setPressed(true, x, y);
-                        checkForLongClick(0);
+                        checkForLongClick(0, x, y);
                     }
                     break;
 
@@ -12889,6 +12956,10 @@
 
             mPrivateFlags |= PFLAG_DIRTY;
 
+            // Release any resources in-case we don't end up drawing again
+            // as anything cached is no longer valid
+            resetDisplayList();
+
             if (invalidateCache) {
                 mPrivateFlags |= PFLAG_INVALIDATED;
                 mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
@@ -19992,13 +20063,14 @@
         }
     }
 
-    private void checkForLongClick(int delayOffset) {
+    private void checkForLongClick(int delayOffset, float x, float y) {
         if ((mViewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) {
             mHasPerformedLongPress = false;
 
             if (mPendingCheckForLongPress == null) {
                 mPendingCheckForLongPress = new CheckForLongPress();
             }
+            mPendingCheckForLongPress.setAnchor(x, y);
             mPendingCheckForLongPress.rememberWindowAttachCount();
             postDelayed(mPendingCheckForLongPress,
                     ViewConfiguration.getLongPressTimeout() - delayOffset);
@@ -20997,7 +21069,40 @@
 
     /** @hide */
     public int getPointerShape(MotionEvent event, float x, float y) {
-        return PointerIcon.STYLE_NOT_SPECIFIED;
+        final int value = (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK);
+        switch (value) {
+            case PFLAG3_POINTER_ICON_NOT_SPECIFIED:
+                return PointerIcon.STYLE_NOT_SPECIFIED;
+            case PFLAG3_POINTER_ICON_NULL:
+                return PointerIcon.STYLE_NULL;
+            case PFLAG3_POINTER_ICON_CUSTOM:
+                return PointerIcon.STYLE_CUSTOM;
+            default:
+                return ((value - PFLAG3_POINTER_ICON_VALUE_START) >> PFLAG3_POINTER_ICON_LSHIFT)
+                        + PointerIcon.STYLE_ARROW;
+        }
+    }
+
+    /** @hide */
+    public void setPointerShape(int pointerShape) {
+        int newValue;
+        if (pointerShape == PointerIcon.STYLE_NOT_SPECIFIED) {
+            newValue = PFLAG3_POINTER_ICON_NOT_SPECIFIED;
+        } else if (pointerShape == PointerIcon.STYLE_NULL) {
+            newValue = PFLAG3_POINTER_ICON_NULL;
+        } else if (pointerShape == PointerIcon.STYLE_CUSTOM) {
+            newValue = PFLAG3_POINTER_ICON_CUSTOM;
+        } else if (pointerShape >= PointerIcon.STYLE_ARROW
+                && pointerShape <= PointerIcon.STYLE_GRABBING) {
+            newValue = ((pointerShape - PointerIcon.STYLE_ARROW) << PFLAG3_POINTER_ICON_LSHIFT)
+                    + PFLAG3_POINTER_ICON_VALUE_START;
+        } else {
+            Log.w(VIEW_LOG_TAG, "Invalid pointer shape " + pointerShape + " is specified.");
+            return;
+        }
+        if (newValue != (mPrivateFlags3 & PFLAG3_POINTER_ICON_MASK)) {
+            mPrivateFlags3 = (mPrivateFlags3 & ~PFLAG3_POINTER_ICON_MASK) | newValue;
+        }
     }
 
     //
@@ -21354,17 +21459,24 @@
 
     private final class CheckForLongPress implements Runnable {
         private int mOriginalWindowAttachCount;
+        private float mX;
+        private float mY;
 
         @Override
         public void run() {
             if (isPressed() && (mParent != null)
                     && mOriginalWindowAttachCount == mWindowAttachCount) {
-                if (performLongClick()) {
+                if (performLongClick(mX, mY)) {
                     mHasPerformedLongPress = true;
                 }
             }
         }
 
+        public void setAnchor(float x, float y) {
+            mX = x;
+            mY = y;
+        }
+
         public void rememberWindowAttachCount() {
             mOriginalWindowAttachCount = mWindowAttachCount;
         }
@@ -21378,7 +21490,7 @@
         public void run() {
             mPrivateFlags &= ~PFLAG_PREPRESSED;
             setPressed(true, x, y);
-            checkForLongClick(ViewConfiguration.getTapTimeout());
+            checkForLongClick(ViewConfiguration.getTapTimeout(), x, y);
         }
     }
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 7c7ad91..db978a6 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -4435,6 +4435,10 @@
                 }
             }
         }
+
+        if (mCurrentDragStartEvent != null && child.getVisibility() == VISIBLE) {
+            notifyChildOfDragStart(child);
+        }
     }
 
     private void addInArray(View child, int index) {
@@ -4686,6 +4690,10 @@
                 mTransientIndices.set(i, oldIndex - 1);
             }
         }
+
+        if (mCurrentDragStartEvent != null) {
+            mChildrenInterestedInDrag.remove(view);
+        }
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7d39a0c..e17bdd7 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4191,7 +4191,10 @@
 
                     if (mPointerIconShape != pointerShape) {
                         mPointerIconShape = pointerShape;
-                        event.getDevice().setPointerShape(pointerShape);
+                        final InputDevice inputDevice = event.getDevice();
+                        if (inputDevice != null) {
+                            inputDevice.setPointerShape(pointerShape);
+                        }
                     }
                 } else if (event.getActionMasked() == MotionEvent.ACTION_HOVER_MOVE) {
                     mPointerIconShape = PointerIcon.STYLE_NOT_SPECIFIED;
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index d9ec866..5d11c8b 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -1156,6 +1156,27 @@
     public abstract void setContentView(View view);
 
     /**
+     * Install a view in the decoration (title) area, to be shown when
+     * the window is in multi-window mode. This view will be placed
+     * next to the window controls.
+     *
+     * The view may be restored to defaults by passing null.
+     *
+     * @param view The desired view to display in window decorations.
+     */
+    public abstract void setDecorView(View view);
+
+    /**
+     * Convenience for
+     * {@link #setDecorView(View)}
+     * to set the custom window decoration from a layout resource. The layout will be inflated
+     * adding all top level views to the decoration
+     *
+     * @param layoutResID Resource ID to be inflated.
+     */
+    public abstract void setDecorView(@LayoutRes int layoutResID);
+
+    /**
      * Set the screen content to an explicit view.  This view is placed
      * directly into the screen's view hierarchy.  It can itself be a complex
      * view hierarchy.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 1b17736..1735e1b 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3083,8 +3083,32 @@
                 return "ACTION_PASTE";
             case ACTION_SET_SELECTION:
                 return "ACTION_SET_SELECTION";
+            case ACTION_EXPAND:
+                return "ACTION_EXPAND";
+            case ACTION_COLLAPSE:
+                return "ACTION_COLLAPSE";
+            case ACTION_DISMISS:
+                return "ACTION_DISMISS";
+            case ACTION_SET_TEXT:
+                return "ACTION_SET_TEXT";
+            case R.id.accessibilityActionShowOnScreen:
+                return "ACTION_SHOW_ON_SCREEN";
+            case R.id.accessibilityActionScrollToPosition:
+                return "ACTION_SCROLL_TO_POSITION";
+            case R.id.accessibilityActionScrollUp:
+                return "ACTION_SCROLL_UP";
+            case R.id.accessibilityActionScrollLeft:
+                return "ACTION_SCROLL_LEFT";
+            case R.id.accessibilityActionScrollDown:
+                return "ACTION_SCROLL_DOWN";
+            case R.id.accessibilityActionScrollRight:
+                return "ACTION_SCROLL_RIGHT";
+            case R.id.accessibilityActionSetProgress:
+                return "ACTION_SET_PROGRESS";
+            case R.id.accessibilityActionContextClick:
+                return "ACTION_CONTEXT_CLICK";
             default:
-                return"ACTION_UNKNOWN";
+                return "ACTION_UNKNOWN";
         }
     }
 
diff --git a/core/java/android/webkit/WebResourceRequest.java b/core/java/android/webkit/WebResourceRequest.java
index 0760d2b..23e9a0d 100644
--- a/core/java/android/webkit/WebResourceRequest.java
+++ b/core/java/android/webkit/WebResourceRequest.java
@@ -40,6 +40,13 @@
     boolean isForMainFrame();
 
     /**
+     * Gets whether the request was a result of a redirect.
+     *
+     * @return whether the request was a result of a redirect.
+     */
+    boolean isRedirect();
+
+    /**
      * Gets whether a gesture (such as a click) was associated with the request.
      * For security reasons in certain situations this method may return false even though the
      * sequence of events which caused the request to be created was initiated by a user gesture.
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index f2bb55a..0e5034d 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -38,12 +38,42 @@
      * @param url The url to be loaded.
      * @return True if the host application wants to leave the current WebView
      *         and handle the url itself, otherwise return false.
+     * @deprecated Use {@link #shouldOverrideUrlLoading(WebView, WebResourceRequest)
+     *             shouldOverrideUrlLoading(WebView, WebResourceRequest)} instead.
      */
+    @Deprecated
     public boolean shouldOverrideUrlLoading(WebView view, String url) {
         return false;
     }
 
     /**
+     * Give the host application a chance to take over the control when a new
+     * url is about to be loaded in the current WebView. If WebViewClient is not
+     * provided, by default WebView will ask Activity Manager to choose the
+     * proper handler for the url. If WebViewClient is provided, return true
+     * means the host application handles the url, while return false means the
+     * current WebView handles the url.
+     *
+     * <p>Notes:
+     * <ul>
+     * <li>This method is not called for requests using the POST &quot;method&quot;.</li>
+     * <li>This method is also called for subframes with non-http schemes, thus it is
+     * strongly disadvised to unconditionally call {@link WebView#loadUrl(String)}
+     * with the request's url from inside the method and then return true,
+     * as this will make WebView to attempt loading a non-http url, and thus fail.</li>
+     * </ul>
+     * </p>
+     *
+     * @param view The WebView that is initiating the callback.
+     * @param request Object containing the details of the request.
+     * @return True if the host application wants to leave the current WebView
+     *         and handle the url itself, otherwise return false.
+     */
+    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
+        return shouldOverrideUrlLoading(view, request.getUrl().toString());
+    }
+
+    /**
      * Notify the host application that a page has started loading. This method
      * is called once for each main frame load so a page with iframes or
      * framesets will call onPageStarted one time for the main frame. This also
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 986c0f8..8e5af79 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -29,6 +29,8 @@
 
 import java.util.Locale;
 
+import libcore.icu.LocaleData;
+
 /**
  * A widget for selecting the time of day, in either 24-hour or AM/PM mode.
  * <p>
@@ -303,6 +305,16 @@
         void onValidationChanged(boolean valid);
     }
 
+    static String[] getAmPmStrings(Context context) {
+        final Locale locale = context.getResources().getConfiguration().locale;
+        final LocaleData d = LocaleData.get(locale);
+
+        final String[] result = new String[2];
+        result[0] = d.amPm[0].length() > 4 ? d.narrowAm : d.amPm[0];
+        result[1] = d.amPm[1].length() > 4 ? d.narrowPm : d.amPm[1];
+        return result;
+    }
+
     /**
      * An abstract class which can be used as a start for TimePicker implementations
      */
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 6d41c1d..4dc5fd3e 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -29,21 +29,22 @@
 import android.text.format.DateUtils;
 import android.text.style.TtsSpan;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.StateSet;
 import android.view.HapticFeedbackConstants;
-import android.view.KeyCharacterMap;
-import android.view.KeyEvent;
 import android.view.LayoutInflater;
+import android.view.MotionEvent;
 import android.view.View;
 import android.view.View.AccessibilityDelegate;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
 import com.android.internal.R;
+import com.android.internal.widget.NumericTextView;
+import com.android.internal.widget.NumericTextView.OnValueChangedListener;
 
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Locale;
 
@@ -52,7 +53,12 @@
  */
 class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements
         RadialTimePickerView.OnValueSelectedListener {
-    private static final String TAG = "TimePickerClockDelegate";
+    /**
+     * Delay in milliseconds before valid but potentially incomplete, for
+     * example "1" but not "12", keyboard edits are propagated from the
+     * hour / minute fields to the radial picker.
+     */
+    private static final long DELAY_COMMIT_MILLIS = 2000;
 
     // Index used by RadialPickerLayout
     private static final int HOUR_INDEX = 0;
@@ -61,9 +67,6 @@
     // NOT a real index for the purpose of what's showing.
     private static final int AMPM_INDEX = 2;
 
-    // Also NOT a real index, just used for keyboard mode.
-    private static final int ENABLE_PICKER_INDEX = 3;
-
     private static final int[] ATTRS_TEXT_COLOR = new int[] {R.attr.textColor};
     private static final int[] ATTRS_DISABLED_ALPHA = new int[] {R.attr.disabledAlpha};
 
@@ -74,18 +77,14 @@
 
     private static final int HOURS_IN_HALF_DAY = 12;
 
-    private final View mHeaderView;
-    private final TextView mHourView;
-    private final TextView mMinuteView;
+    private final NumericTextView mHourView;
+    private final NumericTextView mMinuteView;
     private final View mAmPmLayout;
-    private final CheckedTextView mAmLabel;
-    private final CheckedTextView mPmLabel;
+    private final RadioButton mAmLabel;
+    private final RadioButton mPmLabel;
     private final RadialTimePickerView mRadialTimePickerView;
     private final TextView mSeparatorView;
 
-    private final String mAmText;
-    private final String mPmText;
-
     private boolean mIsEnabled = true;
     private boolean mAllowAutoAdvance;
     private int mInitialHourOfDay;
@@ -93,20 +92,14 @@
     private boolean mIs24HourView;
     private boolean mIsAmPmAtStart;
 
-    // For hardware IME input.
-    private char mPlaceholderText;
-    private String mDoublePlaceholderText;
-    private String mDeletedKeyFormat;
-    private boolean mInKbMode;
-    private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>();
-    private Node mLegalTimesTree;
-    private int mAmKeyCode;
-    private int mPmKeyCode;
-
     // Accessibility strings.
     private String mSelectHours;
     private String mSelectMinutes;
 
+    // Localization data.
+    private boolean mHourFormatShowLeadingZero;
+    private boolean mHourFormatStartsAtZero;
+
     // Most recent time announcement values for accessibility.
     private CharSequence mLastAnnouncedText;
     private boolean mLastAnnouncedIsHour;
@@ -127,43 +120,42 @@
         mSelectHours = res.getString(R.string.select_hours);
         mSelectMinutes = res.getString(R.string.select_minutes);
 
-        String[] amPmStrings = TimePickerSpinnerDelegate.getAmPmStrings(context);
-        mAmText = amPmStrings[0];
-        mPmText = amPmStrings[1];
-
         final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout,
                 R.layout.time_picker_material);
         final View mainView = inflater.inflate(layoutResourceId, delegator);
-
-        mHeaderView = mainView.findViewById(R.id.time_header);
+        final View headerView = mainView.findViewById(R.id.time_header);
+        headerView.setOnTouchListener(new NearestTouchDelegate());
 
         // Set up hour/minute labels.
-        mHourView = (TextView) mainView.findViewById(R.id.hours);
+        mHourView = (NumericTextView) mainView.findViewById(R.id.hours);
         mHourView.setOnClickListener(mClickListener);
+        mHourView.setOnFocusChangeListener(mFocusListener);
+        mHourView.setOnDigitEnteredListener(mDigitEnteredListener);
         mHourView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_hours));
         mSeparatorView = (TextView) mainView.findViewById(R.id.separator);
-        mMinuteView = (TextView) mainView.findViewById(R.id.minutes);
+        mMinuteView = (NumericTextView) mainView.findViewById(R.id.minutes);
         mMinuteView.setOnClickListener(mClickListener);
+        mMinuteView.setOnFocusChangeListener(mFocusListener);
+        mMinuteView.setOnDigitEnteredListener(mDigitEnteredListener);
         mMinuteView.setAccessibilityDelegate(
                 new ClickActionDelegate(context, R.string.select_minutes));
-
-        // Now that we have text appearances out of the way, make sure the hour
-        // and minute views are correctly sized.
-        mHourView.setMinWidth(computeStableWidth(mHourView, 24));
-        mMinuteView.setMinWidth(computeStableWidth(mMinuteView, 60));
-
-        final SpannableStringBuilder amLabel = new SpannableStringBuilder()
-                .append(amPmStrings[0], new TtsSpan.VerbatimBuilder(amPmStrings[0]).build(), 0);
+        mMinuteView.setRange(0, 59);
 
         // Set up AM/PM labels.
         mAmPmLayout = mainView.findViewById(R.id.ampm_layout);
-        mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label);
+        mAmPmLayout.setOnTouchListener(new NearestTouchDelegate());
+
+        final String[] amPmStrings = TimePicker.getAmPmStrings(context);
+        mAmLabel = (RadioButton) mAmPmLayout.findViewById(R.id.am_label);
         mAmLabel.setText(obtainVerbatim(amPmStrings[0]));
         mAmLabel.setOnClickListener(mClickListener);
-        mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label);
+        ensureMinimumTextWidth(mAmLabel);
+
+        mPmLabel = (RadioButton) mAmPmLayout.findViewById(R.id.pm_label);
         mPmLabel.setText(obtainVerbatim(amPmStrings[1]));
         mPmLabel.setOnClickListener(mClickListener);
+        ensureMinimumTextWidth(mPmLabel);
 
         // For the sake of backwards compatibility, attempt to extract the text
         // color from the header time text appearance. If it's set, we'll let
@@ -195,7 +187,7 @@
 
         // Set up header background, if available.
         if (a.hasValueOrEmpty(R.styleable.TimePicker_headerBackground)) {
-            mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
+            headerView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground));
         }
 
         a.recycle();
@@ -207,18 +199,66 @@
 
         mAllowAutoAdvance = true;
 
-        // Set up for keyboard mode.
-        mDoublePlaceholderText = res.getString(R.string.time_placeholder);
-        mDeletedKeyFormat = res.getString(R.string.deleted_key);
-        mPlaceholderText = mDoublePlaceholderText.charAt(0);
-        mAmKeyCode = mPmKeyCode = -1;
-        generateLegalTimesTree();
+        // Updates mHourFormat variables used below.
+        updateHourFormat(mCurrentLocale, mIs24HourView);
 
-        // Initialize with current time
-        final Calendar calendar = Calendar.getInstance(mCurrentLocale);
-        final int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
-        final int currentMinute = calendar.get(Calendar.MINUTE);
-        initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX);
+        // Update hour text field.
+        final int minHour = mHourFormatStartsAtZero ? 0 : 1;
+        final int maxHour = (mIs24HourView ? 23 : 11) + minHour;
+        mHourView.setRange(minHour, maxHour);
+        mHourView.setShowLeadingZeroes(mHourFormatShowLeadingZero);
+
+        // Initialize with current time.
+        mTempCalendar = Calendar.getInstance(mCurrentLocale);
+        final int currentHour = mTempCalendar.get(Calendar.HOUR_OF_DAY);
+        final int currentMinute = mTempCalendar.get(Calendar.MINUTE);
+        initialize(currentHour, currentMinute, mIs24HourView, HOUR_INDEX);
+    }
+
+    /**
+     * Ensures that a TextView is wide enough to contain its text without
+     * wrapping or clipping. Measures the specified view and sets the minimum
+     * width to the view's desired width.
+     *
+     * @param v the text view to measure
+     */
+    private static void ensureMinimumTextWidth(TextView v) {
+        v.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+        // Set both the TextView and the View version of minimum
+        // width because they are subtly different.
+        final int minWidth = v.getMeasuredWidth();
+        v.setMinWidth(minWidth);
+        v.setMinimumWidth(minWidth);
+    }
+
+    /**
+     * Determines how the hour should be formatted and updates member variables
+     * related to hour formatting.
+     *
+     * @param locale the locale in which the view is displayed
+     * @param is24Hour whether the view is in 24-hour (hour-of-day) mode
+     */
+    private void updateHourFormat(Locale locale, boolean is24Hour) {
+        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(
+                locale, is24Hour ? "Hm" : "hm");
+        final int lengthPattern = bestDateTimePattern.length();
+        boolean showLeadingZero = false;
+        char hourFormat = '\0';
+
+        for (int i = 0; i < lengthPattern; i++) {
+            final char c = bestDateTimePattern.charAt(i);
+            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
+                hourFormat = c;
+                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
+                    showLeadingZero = true;
+                }
+                break;
+            }
+        }
+
+        mHourFormatShowLeadingZero = showLeadingZero;
+        mHourFormatStartsAtZero = hourFormat == 'K' || hourFormat == 'H';
     }
 
     private static final CharSequence obtainVerbatim(String text) {
@@ -290,51 +330,24 @@
         }
     }
 
-    private int computeStableWidth(TextView v, int maxNumber) {
-        int maxWidth = 0;
-
-        for (int i = 0; i < maxNumber; i++) {
-            final String text = String.format("%02d", i);
-            v.setText(text);
-            v.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
-
-            final int width = v.getMeasuredWidth();
-            if (width > maxWidth) {
-                maxWidth = width;
-            }
-        }
-
-        return maxWidth;
-    }
-
     private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) {
         mInitialHourOfDay = hourOfDay;
         mInitialMinute = minute;
         mIs24HourView = is24HourView;
-        mInKbMode = false;
         updateUI(index);
     }
 
     private void setupListeners() {
-        mHeaderView.setOnKeyListener(mKeyListener);
-        mHeaderView.setOnFocusChangeListener(mFocusListener);
-        mHeaderView.setFocusable(true);
-
         mRadialTimePickerView.setOnValueSelectedListener(this);
     }
 
     private void updateUI(int index) {
-        // Update RadialPicker values
-        updateRadialPicker(index);
-        // Enable or disable the AM/PM view.
         updateHeaderAmPm();
-        // Update Hour and Minutes
         updateHeaderHour(mInitialHourOfDay, false);
-        // Update time separator
         updateHeaderSeparator();
-        // Update Minutes
         updateHeaderMinute(mInitialMinute, false);
-        // Invalidate everything
+        updateRadialPicker(index);
+
         mDelegator.invalidate();
     }
 
@@ -447,14 +460,11 @@
         if (is24HourView == mIs24HourView) {
             return;
         }
+
         mIs24HourView = is24HourView;
-        generateLegalTimesTree();
-        int hour = mRadialTimePickerView.getCurrentHour();
-        mInitialHourOfDay = hour;
-        updateHeaderHour(hour, false);
-        updateHeaderAmPm();
-        updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing());
-        mDelegator.invalidate();
+        mInitialHourOfDay = getCurrentHour();
+
+        updateUI(mRadialTimePickerView.getCurrentItemShowing());
     }
 
     /**
@@ -499,20 +509,14 @@
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
         return new SavedState(superState, getCurrentHour(), getCurrentMinute(),
-                is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing());
+                is24HourView(), getCurrentItemShowing());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
-        setInKbMode(ss.inKbMode());
-        setTypedTimes(ss.getTypesTimes());
+        final SavedState ss = (SavedState) state;
         initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
         mRadialTimePickerView.invalidate();
-        if (mInKbMode) {
-            tryStartingKbMode(-1);
-            mHourView.invalidate();
-        }
     }
 
     @Override
@@ -543,33 +547,6 @@
     }
 
     /**
-     * Set whether in keyboard mode or not.
-     *
-     * @param inKbMode True means in keyboard mode.
-     */
-    private void setInKbMode(boolean inKbMode) {
-        mInKbMode = inKbMode;
-    }
-
-    /**
-     * @return true if in keyboard mode
-     */
-    private boolean inKbMode() {
-        return mInKbMode;
-    }
-
-    private void setTypedTimes(ArrayList<Integer> typeTimes) {
-        mTypedTimes = typeTimes;
-    }
-
-    /**
-     * @return an array of typed times
-     */
-    private ArrayList<Integer> getTypedTimes() {
-        return mTypedTimes;
-    }
-
-    /**
      * @return the index of the current item showing
      */
     private int getCurrentItemShowing() {
@@ -595,19 +572,14 @@
         private final int mHour;
         private final int mMinute;
         private final boolean mIs24HourMode;
-        private final boolean mInKbMode;
-        private final ArrayList<Integer> mTypedTimes;
         private final int mCurrentItemShowing;
 
         private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
-                           boolean isKbMode, ArrayList<Integer> typedTimes,
-                           int currentItemShowing) {
+                int currentItemShowing) {
             super(superState);
             mHour = hour;
             mMinute = minute;
             mIs24HourMode = is24HourMode;
-            mInKbMode = isKbMode;
-            mTypedTimes = typedTimes;
             mCurrentItemShowing = currentItemShowing;
         }
 
@@ -616,8 +588,6 @@
             mHour = in.readInt();
             mMinute = in.readInt();
             mIs24HourMode = (in.readInt() == 1);
-            mInKbMode = (in.readInt() == 1);
-            mTypedTimes = in.readArrayList(getClass().getClassLoader());
             mCurrentItemShowing = in.readInt();
         }
 
@@ -633,14 +603,6 @@
             return mIs24HourMode;
         }
 
-        public boolean inKbMode() {
-            return mInKbMode;
-        }
-
-        public ArrayList<Integer> getTypesTimes() {
-            return mTypedTimes;
-        }
-
         public int getCurrentItemShowing() {
             return mCurrentItemShowing;
         }
@@ -651,13 +613,11 @@
             dest.writeInt(mHour);
             dest.writeInt(mMinute);
             dest.writeInt(mIs24HourMode ? 1 : 0);
-            dest.writeInt(mInKbMode ? 1 : 0);
-            dest.writeList(mTypedTimes);
             dest.writeInt(mCurrentItemShowing);
         }
 
         @SuppressWarnings({"unused", "hiding"})
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
+        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
             public SavedState createFromParcel(Parcel in) {
                 return new SavedState(in);
             }
@@ -703,12 +663,6 @@
             case AMPM_INDEX:
                 updateAmPmLabelStates(newValue);
                 break;
-            case ENABLE_PICKER_INDEX:
-                if (!isTypedTimeFullyLegal()) {
-                    mTypedTimes.clear();
-                }
-                finishKbMode();
-                break;
         }
 
         if (mOnTimeChangedListener != null) {
@@ -716,61 +670,41 @@
         }
     }
 
-    private void updateHeaderHour(int value, boolean announce) {
-        final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale,
-                (mIs24HourView) ? "Hm" : "hm");
-        final int lengthPattern = bestDateTimePattern.length();
-        boolean hourWithTwoDigit = false;
-        char hourFormat = '\0';
-        // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save
-        // the hour format that we found.
-        for (int i = 0; i < lengthPattern; i++) {
-            final char c = bestDateTimePattern.charAt(i);
-            if (c == 'H' || c == 'h' || c == 'K' || c == 'k') {
-                hourFormat = c;
-                if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) {
-                    hourWithTwoDigit = true;
-                }
-                break;
-            }
+    /**
+     * Converts hour-of-day (0-23) time into a localized hour number.
+     *
+     * @param hourOfDay the hour-of-day (0-23)
+     * @return a localized hour number
+     */
+    private int getLocalizedHour(int hourOfDay) {
+        if (!mIs24HourView) {
+            // Convert to hour-of-am-pm.
+            hourOfDay %= 12;
         }
-        final String format;
-        if (hourWithTwoDigit) {
-            format = "%02d";
-        } else {
-            format = "%d";
+
+        if (!mHourFormatStartsAtZero && hourOfDay == 0) {
+            // Convert to clock-hour (either of-day or of-am-pm).
+            hourOfDay = mIs24HourView ? 24 : 12;
         }
-        if (mIs24HourView) {
-            // 'k' means 1-24 hour
-            if (hourFormat == 'k' && value == 0) {
-                value = 24;
-            }
-        } else {
-            // 'K' means 0-11 hour
-            value = modulo12(value, hourFormat == 'K');
-        }
-        CharSequence text = String.format(format, value);
-        mHourView.setText(text);
+
+        return hourOfDay;
+    }
+
+    private void updateHeaderHour(int hourOfDay, boolean announce) {
+        final int localizedHour = getLocalizedHour(hourOfDay);
+        mHourView.setValue(localizedHour);
+
         if (announce) {
-            tryAnnounceForAccessibility(text, true);
+            tryAnnounceForAccessibility(mHourView.getText(), true);
         }
     }
 
-    private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
-        if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
-            // TODO: Find a better solution, potentially live regions?
-            mDelegator.announceForAccessibility(text);
-            mLastAnnouncedText = text;
-            mLastAnnouncedIsHour = isHour;
-        }
-    }
+    private void updateHeaderMinute(int minuteOfHour, boolean announce) {
+        mMinuteView.setValue(minuteOfHour);
 
-    private static int modulo12(int n, boolean startWithZero) {
-        int value = n % 12;
-        if (value == 0 && !startWithZero) {
-            value = 12;
+        if (announce) {
+            tryAnnounceForAccessibility(mMinuteView.getText(), false);
         }
-        return value;
     }
 
     /**
@@ -812,14 +746,12 @@
         return -1;
     }
 
-    private void updateHeaderMinute(int value, boolean announceForAccessibility) {
-        if (value == 60) {
-            value = 0;
-        }
-        final CharSequence text = String.format(mCurrentLocale, "%02d", value);
-        mMinuteView.setText(text);
-        if (announceForAccessibility) {
-            tryAnnounceForAccessibility(text, false);
+    private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) {
+        if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) {
+            // TODO: Find a better solution, potentially live regions?
+            mDelegator.announceForAccessibility(text);
+            mLastAnnouncedText = text;
+            mLastAnnouncedIsHour = isHour;
         }
     }
 
@@ -848,477 +780,82 @@
         mRadialTimePickerView.setAmOrPm(amOrPm);
     }
 
-    /**
-     * For keyboard mode, processes key events.
-     *
-     * @param keyCode the pressed key.
-     *
-     * @return true if the key was successfully processed, false otherwise.
-     */
-    private boolean processKeyUp(int keyCode) {
-        if (keyCode == KeyEvent.KEYCODE_DEL) {
-            if (mInKbMode) {
-                if (!mTypedTimes.isEmpty()) {
-                    int deleted = deleteLastTypedKey();
-                    String deletedKeyStr;
-                    if (deleted == getAmOrPmKeyCode(AM)) {
-                        deletedKeyStr = mAmText;
-                    } else if (deleted == getAmOrPmKeyCode(PM)) {
-                        deletedKeyStr = mPmText;
-                    } else {
-                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
+    private final OnValueChangedListener mDigitEnteredListener = new OnValueChangedListener() {
+        @Override
+        public void onValueChanged(NumericTextView view, int value,
+                boolean isValid, boolean isFinished) {
+            final Runnable commitCallback;
+            final View nextFocusTarget;
+            if (view == mHourView) {
+                commitCallback = mCommitHour;
+                nextFocusTarget = view.isFocused() ? mMinuteView : null;
+            } else if (view == mMinuteView) {
+                commitCallback = mCommitMinute;
+                nextFocusTarget = null;
+            } else {
+                return;
+            }
+
+            view.removeCallbacks(commitCallback);
+
+            if (isValid) {
+                if (isFinished) {
+                    // Done with hours entry, make visual updates
+                    // immediately and move to next focus if needed.
+                    commitCallback.run();
+
+                    if (nextFocusTarget != null) {
+                        nextFocusTarget.requestFocus();
                     }
-                    mDelegator.announceForAccessibility(
-                            String.format(mDeletedKeyFormat, deletedKeyStr));
-                    updateDisplay(true);
-                }
-            }
-        } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
-                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
-                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
-                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
-                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9
-                || (!mIs24HourView &&
-                (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) {
-            if (!mInKbMode) {
-                if (mRadialTimePickerView == null) {
-                    // Something's wrong, because time picker should definitely not be null.
-                    Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null.");
-                    return true;
-                }
-                mTypedTimes.clear();
-                tryStartingKbMode(keyCode);
-                return true;
-            }
-            // We're already in keyboard mode.
-            if (addKeyIfLegal(keyCode)) {
-                updateDisplay(false);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Try to start keyboard mode with the specified key.
-     *
-     * @param keyCode The key to use as the first press. Keyboard mode will not be started if the
-     * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting
-     * key.
-     */
-    private void tryStartingKbMode(int keyCode) {
-        if (keyCode == -1 || addKeyIfLegal(keyCode)) {
-            mInKbMode = true;
-            onValidationChanged(false);
-            updateDisplay(false);
-            mRadialTimePickerView.setInputEnabled(false);
-        }
-    }
-
-    private boolean addKeyIfLegal(int keyCode) {
-        // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode,
-        // we'll need to see if AM/PM have been typed.
-        if ((mIs24HourView && mTypedTimes.size() == 4) ||
-                (!mIs24HourView && isTypedTimeFullyLegal())) {
-            return false;
-        }
-
-        mTypedTimes.add(keyCode);
-        if (!isTypedTimeLegalSoFar()) {
-            deleteLastTypedKey();
-            return false;
-        }
-
-        int val = getValFromKeyCode(keyCode);
-        mDelegator.announceForAccessibility(String.format("%d", val));
-        // Automatically fill in 0's if AM or PM was legally entered.
-        if (isTypedTimeFullyLegal()) {
-            if (!mIs24HourView && mTypedTimes.size() <= 3) {
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-                mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0);
-            }
-            onValidationChanged(true);
-        }
-
-        return true;
-    }
-
-    /**
-     * Traverse the tree to see if the keys that have been typed so far are legal as is,
-     * or may become legal as more keys are typed (excluding backspace).
-     */
-    private boolean isTypedTimeLegalSoFar() {
-        Node node = mLegalTimesTree;
-        for (int keyCode : mTypedTimes) {
-            node = node.canReach(keyCode);
-            if (node == null) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Check if the time that has been typed so far is completely legal, as is.
-     */
-    private boolean isTypedTimeFullyLegal() {
-        if (mIs24HourView) {
-            // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note:
-            // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode.
-            int[] values = getEnteredTime(null);
-            return (values[0] >= 0 && values[1] >= 0 && values[1] < 60);
-        } else {
-            // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be
-            // legally added at specific times based on the tree's algorithm.
-            return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) ||
-                    mTypedTimes.contains(getAmOrPmKeyCode(PM)));
-        }
-    }
-
-    private int deleteLastTypedKey() {
-        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
-        if (!isTypedTimeFullyLegal()) {
-            onValidationChanged(false);
-        }
-        return deleted;
-    }
-
-    /**
-     * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time.
-     */
-    private void finishKbMode() {
-        mInKbMode = false;
-        if (!mTypedTimes.isEmpty()) {
-            int values[] = getEnteredTime(null);
-            mRadialTimePickerView.setCurrentHour(values[0]);
-            mRadialTimePickerView.setCurrentMinute(values[1]);
-            if (!mIs24HourView) {
-                mRadialTimePickerView.setAmOrPm(values[2]);
-            }
-            mTypedTimes.clear();
-        }
-        updateDisplay(false);
-        mRadialTimePickerView.setInputEnabled(true);
-    }
-
-    /**
-     * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is
-     * empty, either show an empty display (filled with the placeholder text), or update from the
-     * timepicker's values.
-     *
-     * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text.
-     * Otherwise, revert to the timepicker's values.
-     */
-    private void updateDisplay(boolean allowEmptyDisplay) {
-        if (!allowEmptyDisplay && mTypedTimes.isEmpty()) {
-            int hour = mRadialTimePickerView.getCurrentHour();
-            int minute = mRadialTimePickerView.getCurrentMinute();
-            updateHeaderHour(hour, false);
-            updateHeaderMinute(minute, false);
-            if (!mIs24HourView) {
-                updateAmPmLabelStates(hour < 12 ? AM : PM);
-            }
-            setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true);
-            onValidationChanged(true);
-        } else {
-            boolean[] enteredZeros = {false, false};
-            int[] values = getEnteredTime(enteredZeros);
-            String hourFormat = enteredZeros[0] ? "%02d" : "%2d";
-            String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d";
-            String hourStr = (values[0] == -1) ? mDoublePlaceholderText :
-                    String.format(hourFormat, values[0]).replace(' ', mPlaceholderText);
-            String minuteStr = (values[1] == -1) ? mDoublePlaceholderText :
-                    String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
-            mHourView.setText(hourStr);
-            mHourView.setActivated(false);
-            mMinuteView.setText(minuteStr);
-            mMinuteView.setActivated(false);
-            if (!mIs24HourView) {
-                updateAmPmLabelStates(values[2]);
-            }
-        }
-    }
-
-    private int getValFromKeyCode(int keyCode) {
-        switch (keyCode) {
-            case KeyEvent.KEYCODE_0:
-                return 0;
-            case KeyEvent.KEYCODE_1:
-                return 1;
-            case KeyEvent.KEYCODE_2:
-                return 2;
-            case KeyEvent.KEYCODE_3:
-                return 3;
-            case KeyEvent.KEYCODE_4:
-                return 4;
-            case KeyEvent.KEYCODE_5:
-                return 5;
-            case KeyEvent.KEYCODE_6:
-                return 6;
-            case KeyEvent.KEYCODE_7:
-                return 7;
-            case KeyEvent.KEYCODE_8:
-                return 8;
-            case KeyEvent.KEYCODE_9:
-                return 9;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Get the currently-entered time, as integer values of the hours and minutes typed.
-     *
-     * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which
-     * may then be used for the caller to know whether zeros had been explicitly entered as either
-     * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's.
-     *
-     * @return A size-3 int array. The first value will be the hours, the second value will be the
-     * minutes, and the third will be either AM or PM.
-     */
-    private int[] getEnteredTime(boolean[] enteredZeros) {
-        int amOrPm = -1;
-        int startIndex = 1;
-        if (!mIs24HourView && isTypedTimeFullyLegal()) {
-            int keyCode = mTypedTimes.get(mTypedTimes.size() - 1);
-            if (keyCode == getAmOrPmKeyCode(AM)) {
-                amOrPm = AM;
-            } else if (keyCode == getAmOrPmKeyCode(PM)){
-                amOrPm = PM;
-            }
-            startIndex = 2;
-        }
-        int minute = -1;
-        int hour = -1;
-        for (int i = startIndex; i <= mTypedTimes.size(); i++) {
-            int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i));
-            if (i == startIndex) {
-                minute = val;
-            } else if (i == startIndex+1) {
-                minute += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[1] = true;
-                }
-            } else if (i == startIndex+2) {
-                hour = val;
-            } else if (i == startIndex+3) {
-                hour += 10 * val;
-                if (enteredZeros != null && val == 0) {
-                    enteredZeros[0] = true;
+                } else {
+                    // May still be making changes. Postpone visual
+                    // updates to prevent distracting the user.
+                    view.postDelayed(commitCallback, DELAY_COMMIT_MILLIS);
                 }
             }
         }
+    };
 
-        return new int[] { hour, minute, amOrPm };
-    }
+    private final Runnable mCommitHour = new Runnable() {
+        @Override
+        public void run() {
+            setCurrentHour(mHourView.getValue());
+        }
+    };
 
-    /**
-     * Get the keycode value for AM and PM in the current language.
-     */
-    private int getAmOrPmKeyCode(int amOrPm) {
-        // Cache the codes.
-        if (mAmKeyCode == -1 || mPmKeyCode == -1) {
-            // Find the first character in the AM/PM text that is unique.
-            final KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD);
-            final CharSequence amText = mAmText.toLowerCase(mCurrentLocale);
-            final CharSequence pmText = mPmText.toLowerCase(mCurrentLocale);
-            final int N = Math.min(amText.length(), pmText.length());
-            for (int i = 0; i < N; i++) {
-                final char amChar = amText.charAt(i);
-                final char pmChar = pmText.charAt(i);
-                if (amChar != pmChar) {
-                    // There should be 4 events: a down and up for both AM and PM.
-                    final KeyEvent[] events = kcm.getEvents(new char[] { amChar, pmChar });
-                    if (events != null && events.length == 4) {
-                        mAmKeyCode = events[0].getKeyCode();
-                        mPmKeyCode = events[2].getKeyCode();
-                    } else {
-                        Log.e(TAG, "Unable to find keycodes for AM and PM.");
-                    }
-                    break;
+    private final Runnable mCommitMinute = new Runnable() {
+        @Override
+        public void run() {
+            setCurrentMinute(mMinuteView.getValue());
+        }
+    };
+
+    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(View v, boolean focused) {
+            if (focused) {
+                switch (v.getId()) {
+                    case R.id.am_label:
+                        setAmOrPm(AM);
+                        break;
+                    case R.id.pm_label:
+                        setAmOrPm(PM);
+                        break;
+                    case R.id.hours:
+                        setCurrentItemShowing(HOUR_INDEX, true, true);
+                        break;
+                    case R.id.minutes:
+                        setCurrentItemShowing(MINUTE_INDEX, true, true);
+                        break;
+                    default:
+                        // Failed to handle this click, don't vibrate.
+                        return;
                 }
+
+                tryVibrate();
             }
         }
-
-        if (amOrPm == AM) {
-            return mAmKeyCode;
-        } else if (amOrPm == PM) {
-            return mPmKeyCode;
-        }
-
-        return -1;
-    }
-
-    /**
-     * Create a tree for deciding what keys can legally be typed.
-     */
-    private void generateLegalTimesTree() {
-        // Create a quick cache of numbers to their keycodes.
-        final int k0 = KeyEvent.KEYCODE_0;
-        final int k1 = KeyEvent.KEYCODE_1;
-        final int k2 = KeyEvent.KEYCODE_2;
-        final int k3 = KeyEvent.KEYCODE_3;
-        final int k4 = KeyEvent.KEYCODE_4;
-        final int k5 = KeyEvent.KEYCODE_5;
-        final int k6 = KeyEvent.KEYCODE_6;
-        final int k7 = KeyEvent.KEYCODE_7;
-        final int k8 = KeyEvent.KEYCODE_8;
-        final int k9 = KeyEvent.KEYCODE_9;
-
-        // The root of the tree doesn't contain any numbers.
-        mLegalTimesTree = new Node();
-        if (mIs24HourView) {
-            // We'll be re-using these nodes, so we'll save them.
-            Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5);
-            Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            // The first digit must be followed by the second digit.
-            minuteFirstDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 0-1.
-            Node firstDigit = new Node(k0, k1);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 0-1, the second digit may be 0-5.
-            Node secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We may now be followed by the first minute digit. E.g. 00:09, 15:58.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9.
-            Node thirdDigit = new Node(k6, k7, k8, k9);
-            // The time must now be finished. E.g. 0:55, 1:08.
-            secondDigit.addChild(thirdDigit);
-
-            // When the first digit is 0-1, the second digit may be 6-9.
-            secondDigit = new Node(k6, k7, k8, k9);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 06:50, 18:20.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // The first digit may be 2.
-            firstDigit = new Node(k2);
-            mLegalTimesTree.addChild(firstDigit);
-
-            // When the first digit is 2, the second digit may be 0-3.
-            secondDigit = new Node(k0, k1, k2, k3);
-            firstDigit.addChild(secondDigit);
-            // We must now be followed by the first minute digit. E.g. 20:50, 23:09.
-            secondDigit.addChild(minuteFirstDigit);
-
-            // When the first digit is 2, the second digit may be 4-5.
-            secondDigit = new Node(k4, k5);
-            firstDigit.addChild(secondDigit);
-            // We must now be followd by the last minute digit. E.g. 2:40, 2:53.
-            secondDigit.addChild(minuteSecondDigit);
-
-            // The first digit may be 3-9.
-            firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We must now be followed by the first minute digit. E.g. 3:57, 8:12.
-            firstDigit.addChild(minuteFirstDigit);
-        } else {
-            // We'll need to use the AM/PM node a lot.
-            // Set up AM and PM to respond to "a" and "p".
-            Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM));
-
-            // The first hour digit may be 1.
-            Node firstDigit = new Node(k1);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour times. E.g. 1pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 0-2.
-            Node secondDigit = new Node(k0, k1, k2);
-            firstDigit.addChild(secondDigit);
-            // Also for quick input of on-the-hour times. E.g. 10pm, 12am.
-            secondDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5.
-            Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5);
-            secondDigit.addChild(thirdDigit);
-            // The time may be finished now. E.g. 1:02pm, 1:25am.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5,
-            // the fourth digit may be 0-9.
-            Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            thirdDigit.addChild(fourthDigit);
-            // The time must be finished now. E.g. 10:49am, 12:40pm.
-            fourthDigit.addChild(ampm);
-
-            // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9.
-            thirdDigit = new Node(k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:08am, 1:26pm.
-            thirdDigit.addChild(ampm);
-
-            // When the first digit is 1, the second digit may be 3-5.
-            secondDigit = new Node(k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 1:39am, 1:50pm.
-            thirdDigit.addChild(ampm);
-
-            // The hour digit may be 2-9.
-            firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9);
-            mLegalTimesTree.addChild(firstDigit);
-            // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm.
-            firstDigit.addChild(ampm);
-
-            // When the first digit is 2-9, the second digit may be 0-5.
-            secondDigit = new Node(k0, k1, k2, k3, k4, k5);
-            firstDigit.addChild(secondDigit);
-
-            // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9.
-            thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9);
-            secondDigit.addChild(thirdDigit);
-            // The time must be finished now. E.g. 2:57am, 9:30pm.
-            thirdDigit.addChild(ampm);
-        }
-    }
-
-    /**
-     * Simple node class to be used for traversal to check for legal times.
-     * mLegalKeys represents the keys that can be typed to get to the node.
-     * mChildren are the children that can be reached from this node.
-     */
-    private class Node {
-        private int[] mLegalKeys;
-        private ArrayList<Node> mChildren;
-
-        public Node(int... legalKeys) {
-            mLegalKeys = legalKeys;
-            mChildren = new ArrayList<Node>();
-        }
-
-        public void addChild(Node child) {
-            mChildren.add(child);
-        }
-
-        public boolean containsKey(int key) {
-            for (int i = 0; i < mLegalKeys.length; i++) {
-                if (mLegalKeys[i] == key) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        public Node canReach(int key) {
-            if (mChildren == null) {
-                return null;
-            }
-            for (Node child : mChildren) {
-                if (child.containsKey(key)) {
-                    return child;
-                }
-            }
-            return null;
-        }
-    }
+    };
 
     private final View.OnClickListener mClickListener = new View.OnClickListener() {
         @Override
@@ -1347,28 +884,55 @@
         }
     };
 
-    private final View.OnKeyListener mKeyListener = new View.OnKeyListener() {
-        @Override
-        public boolean onKey(View v, int keyCode, KeyEvent event) {
-            if (event.getAction() == KeyEvent.ACTION_UP) {
-                return processKeyUp(keyCode);
+    /**
+     * Delegates unhandled touches in a view group to the nearest child view.
+     */
+    private static class NearestTouchDelegate implements View.OnTouchListener {
+            private View mInitialTouchTarget;
+
+            @Override
+            public boolean onTouch(View view, MotionEvent motionEvent) {
+                final int actionMasked = motionEvent.getActionMasked();
+                if (actionMasked == MotionEvent.ACTION_DOWN) {
+                    mInitialTouchTarget = findNearestChild((ViewGroup) view,
+                            (int) motionEvent.getX(), (int) motionEvent.getY());
+                }
+
+                final View child = mInitialTouchTarget;
+                if (child == null) {
+                    return false;
+                }
+
+                final float offsetX = view.getScrollX() - child.getLeft();
+                final float offsetY = view.getScrollY() - child.getTop();
+                motionEvent.offsetLocation(offsetX, offsetY);
+                final boolean handled = child.dispatchTouchEvent(motionEvent);
+                motionEvent.offsetLocation(-offsetX, -offsetY);
+
+                if (actionMasked == MotionEvent.ACTION_UP
+                        || actionMasked == MotionEvent.ACTION_CANCEL) {
+                    mInitialTouchTarget = null;
+                }
+
+                return handled;
             }
-            return false;
-        }
-    };
 
-    private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() {
-        @Override
-        public void onFocusChange(View v, boolean hasFocus) {
-            if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) {
-                finishKbMode();
+        private View findNearestChild(ViewGroup v, int x, int y) {
+            View bestChild = null;
+            int bestDist = Integer.MAX_VALUE;
 
-                if (mOnTimeChangedListener != null) {
-                    mOnTimeChangedListener.onTimeChanged(mDelegator,
-                            mRadialTimePickerView.getCurrentHour(),
-                            mRadialTimePickerView.getCurrentMinute());
+            for (int i = 0, count = v.getChildCount(); i < count; i++) {
+                final View child = v.getChildAt(i);
+                final int dX = x - (child.getLeft() + child.getWidth() / 2);
+                final int dY = y - (child.getTop() + child.getHeight() / 2);
+                final int dist = dX * dX + dY * dY;
+                if (bestDist > dist) {
+                    bestChild = child;
+                    bestDist = dist;
                 }
             }
+
+            return bestChild;
         }
-    };
+    }
 }
diff --git a/core/java/com/android/internal/alsa/AlsaCardsParser.java b/core/java/com/android/internal/alsa/AlsaCardsParser.java
index 67ee085..17e8c9c 100644
--- a/core/java/com/android/internal/alsa/AlsaCardsParser.java
+++ b/core/java/com/android/internal/alsa/AlsaCardsParser.java
@@ -94,6 +94,12 @@
         public String textFormat() {
           return mCardName + " : " + mCardDescription;
         }
+
+        public void log(int listIndex) {
+            Slog.d(TAG, "" + listIndex +
+                " [" + mCardNum + " " + mCardName + " : " + mCardDescription +
+                " usb:" + mIsUsb);
+        }
     }
 
     public AlsaCardsParser() {}
@@ -169,9 +175,41 @@
 
     // return -1 if none found
     public int getDefaultUsbCard() {
+        // save the current list of devices
+        ArrayList<AlsaCardsParser.AlsaCardRecord> prevRecs = mCardRecords;
+        if (DEBUG) {
+            LogDevices("Previous Devices:", prevRecs);
+        }
+
+        // get the new list of devices
+        scan();
+        if (DEBUG) {
+            LogDevices("Current Devices:", mCardRecords);
+        }
+
+        // Calculate the difference between the old and new device list
+        ArrayList<AlsaCardRecord> newRecs = getNewCardRecords(prevRecs);
+        if (DEBUG) {
+            LogDevices("New Devices:", newRecs);
+        }
+
         // Choose the most-recently added EXTERNAL card
+        // Check recently added devices
+        for (AlsaCardRecord rec : newRecs) {
+            if (DEBUG) {
+                Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
+            }
+            if (rec.mIsUsb) {
+                // Found it
+                return rec.mCardNum;
+            }
+        }
+
         // or return the first added EXTERNAL card?
-        for (AlsaCardRecord rec : mCardRecords) {
+        for (AlsaCardRecord rec : prevRecs) {
+            if (DEBUG) {
+                Slog.d(TAG, rec.mCardName + " card:" + rec.mCardNum + " usb:" + rec.mIsUsb);
+            }
             if (rec.mIsUsb) {
                 return rec.mCardNum;
             }
@@ -183,11 +221,17 @@
     public int getDefaultCard() {
         // return an external card if possible
         int card = getDefaultUsbCard();
+        if (DEBUG) {
+            Slog.d(TAG, "getDefaultCard() default usb card:" + card);
+        }
 
         if (card < 0 && getNumCardRecords() > 0) {
             // otherwise return the (internal) card with the highest number
             card = getCardRecordAt(getNumCardRecords() - 1).mCardNum;
         }
+        if (DEBUG) {
+            Slog.d(TAG, "  returns card:" + card);
+        }
         return card;
     }
 
@@ -222,4 +266,13 @@
             }
         }
     }
+
+    static public void LogDevices(String caption, ArrayList<AlsaCardRecord> deviceList) {
+        Slog.d(TAG, caption + " ----------------");
+        int listIndex = 0;
+        for (AlsaCardRecord device : deviceList) {
+            device.log(listIndex++);
+        }
+        Slog.d(TAG, "----------------");
+    }
 }
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
index aa603c1..4f17c39 100644
--- a/core/java/com/android/internal/policy/DecorContext.java
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -17,7 +17,6 @@
 package com.android.internal.policy;
 
 import android.content.Context;
-import android.content.res.TypedArray;
 import android.view.ContextThemeWrapper;
 import android.view.WindowManager;
 import android.view.WindowManagerImpl;
@@ -31,7 +30,6 @@
 class DecorContext extends ContextThemeWrapper {
     private PhoneWindow mPhoneWindow;
     private WindowManager mWindowManager;
-    private TypedArray mWindowStyle;
 
     public DecorContext(Context context) {
         super(context, null);
@@ -54,13 +52,4 @@
         }
         return super.getSystemService(name);
     }
-
-    public TypedArray getWindowStyle() {
-        synchronized (this) {
-            if (mWindowStyle == null) {
-                mWindowStyle = obtainStyledAttributes(com.android.internal.R.styleable.Window);
-            }
-            return mWindowStyle;
-        }
-    }
 }
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 8b81812..b3bd46d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.INVALID_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -31,7 +32,6 @@
 import android.animation.ObjectAnimator;
 import android.app.ActivityManagerNative;
 import android.app.SearchManager;
-import android.graphics.drawable.ColorDrawable;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -123,6 +123,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 import android.widget.ImageView;
 import android.widget.PopupWindow;
 import android.widget.ProgressBar;
@@ -469,6 +470,30 @@
     }
 
     @Override
+    public void setDecorView(int layoutResID) {
+        View v = mLayoutInflater.inflate(layoutResID, null);
+        setDecorView(v);
+    }
+
+    @Override
+    public void setDecorView(View view) {
+        if (mContentParent == null) {
+            installDecor();
+        }
+
+        LinearLayout clientDecorPlaceholder =
+                (LinearLayout) findViewById(R.id.client_decor_placeholder);
+
+        if (clientDecorPlaceholder != null) {
+            clientDecorPlaceholder.removeAllViews();
+
+            if (view != null) {
+                clientDecorPlaceholder.addView(view);
+            }
+        }
+    }
+
+    @Override
     public void addContentView(View view, ViewGroup.LayoutParams params) {
         if (mContentParent == null) {
             installDecor();
@@ -5418,7 +5443,7 @@
      * @Return Returns true if the window should show a shadow.
      **/
     private static boolean nonClientDecorHasShadow(int workspaceId) {
-        return workspaceId == FREEFORM_WORKSPACE_STACK_ID;
+        return workspaceId == FREEFORM_WORKSPACE_STACK_ID || workspaceId == PINNED_STACK_ID;
     }
 
     @Override
@@ -5438,20 +5463,7 @@
      * */
     private Drawable getResizingBackgroundDrawable() {
         final Context context = mDecor.getContext();
-        final TypedArray windowStyle;
-        if (context instanceof DecorContext) {
-            windowStyle = ((DecorContext) context).getWindowStyle();
-        } else {
-            windowStyle = getWindowStyle();
-        }
-        final int resourceId =
-                windowStyle.getResourceId(R.styleable.Window_windowResizingBackground, 0);
-        if (resourceId != 0) {
-            return context.getDrawable(resourceId);
-        }
 
-        // The app didn't set a resizing background color. In this case we try to use the app's
-        // background drawable for the resizing background.
         if (mBackgroundResource != 0) {
             final Drawable drawable = context.getDrawable(mBackgroundResource);
             if (drawable != null) {
@@ -5459,8 +5471,6 @@
             }
         }
 
-        // The app background drawable isn't currently set. This might be because the app cleared
-        // it. In this case we try to use the app's background fallback drawable.
         if (mBackgroundFallbackResource != 0) {
             final Drawable fallbackDrawable = context.getDrawable(mBackgroundFallbackResource);
             if (fallbackDrawable != null) {
@@ -5468,7 +5478,9 @@
             }
         }
 
-        return new ColorDrawable(context.getResources().getInteger(
-                com.android.internal.R.integer.config_windowResizingBackgroundColorARGB));
+        // We shouldn't really get here as the background fallback should be always available since
+        // it is defaulted by the system.
+        Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + this);
+        return null;
     }
 }
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 5d502c9..be9be11 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -428,8 +428,7 @@
 
         // The render nodes for the multi threaded renderer.
         private ThreadedRenderer mRenderer;
-        private RenderNode mFrameNode;
-        private RenderNode mBackdropNode;
+        private RenderNode mFrameAndBackdropNode;
 
         private final Rect mOldTargetRect = new Rect();
         private final Rect mNewTargetRect = new Rect();
@@ -450,13 +449,11 @@
             setName("ResizeFrame");
             mRenderer = renderer;
 
-            // Create the render nodes for our frame and backdrop which can be resized independently
-            // from the content.
-            mFrameNode = RenderNode.create("FrameNode", null);
-            mBackdropNode = RenderNode.create("BackdropNode", null);
+            // Create a render node for the content and frame backdrop
+            // which can be resized independently from the content.
+            mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null);
 
-            mRenderer.addRenderNode(mFrameNode, false);
-            mRenderer.addRenderNode(mBackdropNode, true);
+            mRenderer.addRenderNode(mFrameAndBackdropNode, true);
 
             // Set the initial bounds and draw once so that we do not get a broken frame.
             mTargetRect.set(initialBounds);
@@ -504,10 +501,9 @@
                     // Invalidate the current content bounds.
                     mRenderer.setContentDrawBounds(0, 0, 0, 0);
 
-                    // Remove the render nodes again
+                    // Remove the render node again
                     // (see comment above - better to do that only once).
-                    mRenderer.removeRenderNode(mFrameNode);
-                    mRenderer.removeRenderNode(mBackdropNode);
+                    mRenderer.removeRenderNode(mFrameAndBackdropNode);
 
                     mRenderer = null;
 
@@ -575,7 +571,7 @@
 
                 mRenderer.setContentDrawBounds(
                         mLastXOffset,
-                        mLastYOffset + mLastCaptionHeight,
+                        mLastYOffset,
                         mLastXOffset + mLastContentWidth,
                         mLastYOffset + mLastCaptionHeight + mLastContentHeight);
                 // If this was the first call and changeWindowSizeLocked got already called prior
@@ -623,30 +619,20 @@
             final int width = newBounds.width();
             final int height = newBounds.height();
 
-            // Produce the draw calls.
-            // TODO(skuhne): Create a separate caption view which draws this. If the shadow should
-            // be resized while the window resizes, this hierarchy needs to have the elevation.
-            // That said - it is probably no good idea to draw the shadow every time since it costs
-            // a considerable time which we should rather spend for resizing the content and it does
-            // barely show while the entire screen is moving.
-            mFrameNode.setLeftTopRightBottom(left, top, left + width, top + mLastCaptionHeight);
-            DisplayListCanvas canvas = mFrameNode.start(width, height);
+            mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
+
+            // Draw the caption and content backdrops in to our render node.
+            DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
             mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
             mCaptionBackgroundDrawable.draw(canvas);
-            mFrameNode.end(canvas);
-
-            mBackdropNode.setLeftTopRightBottom(left, top + mLastCaptionHeight, left + width,
-                    top + height);
 
             // The backdrop: clear everything with the background. Clipping is done elsewhere.
-            canvas = mBackdropNode.start(width, height - mLastCaptionHeight);
-            mResizingBackgroundDrawable.setBounds(0, 0, left + width, top + height);
+            mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
             mResizingBackgroundDrawable.draw(canvas);
-            mBackdropNode.end(canvas);
+            mFrameAndBackdropNode.end(canvas);
 
-            // We need to render both rendered nodes explicitly.
-            mRenderer.drawRenderNode(mFrameNode);
-            mRenderer.drawRenderNode(mBackdropNode);
+            // We need to render the node explicitly
+            mRenderer.drawRenderNode(mFrameAndBackdropNode);
 
             reportDrawIfNeeded();
         }
diff --git a/core/java/com/android/internal/widget/NumericTextView.java b/core/java/com/android/internal/widget/NumericTextView.java
new file mode 100644
index 0000000..27c5834
--- /dev/null
+++ b/core/java/com/android/internal/widget/NumericTextView.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.widget;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.StateSet;
+import android.view.KeyEvent;
+import android.widget.TextView;
+
+/**
+ * Extension of TextView that can handle displaying and inputting a range of
+ * numbers.
+ * <p>
+ * Clients of this view should never call {@link #setText(CharSequence)} or
+ * {@link #setHint(CharSequence)} directly. Instead, they should call
+ * {@link #setValue(int)} to modify the currently displayed value.
+ */
+public class NumericTextView extends TextView {
+    private static final int RADIX = 10;
+    private static final double LOG_RADIX = Math.log(RADIX);
+
+    private int mMinValue = 0;
+    private int mMaxValue = 99;
+
+    /** Number of digits in the maximum value. */
+    private int mMaxCount = 2;
+
+    private boolean mShowLeadingZeroes = true;
+
+    private int mValue;
+
+    /** Number of digits entered during editing mode. */
+    private int mCount;
+
+    /** Used to restore the value after an aborted edit. */
+    private int mPreviousValue;
+
+    private OnValueChangedListener mListener;
+
+    public NumericTextView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        // Generate the hint text color based on disabled state.
+        final int textColorDisabled = getTextColors().getColorForState(StateSet.get(0), 0);
+        setHintTextColor(textColorDisabled);
+
+        setFocusable(true);
+    }
+
+    @Override
+    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
+        super.onFocusChanged(focused, direction, previouslyFocusedRect);
+
+        if (focused) {
+            mPreviousValue = mValue;
+            mValue = 0;
+            mCount = 0;
+
+            // Transfer current text to hint.
+            setHint(getText());
+            setText("");
+        } else {
+            if (mCount == 0) {
+                // No digits were entered, revert to previous value.
+                mValue = mPreviousValue;
+
+                setText(getHint());
+                setHint("");
+            }
+
+            // Ensure the committed value is within range.
+            if (mValue < mMinValue) {
+                mValue = mMinValue;
+            }
+
+            setValue(mValue);
+
+            if (mListener != null) {
+                mListener.onValueChanged(this, mValue, true, true);
+            }
+        }
+    }
+
+    /**
+     * Sets the currently displayed value.
+     * <p>
+     * The specified {@code value} must be within the range specified by
+     * {@link #setRange(int, int)} (e.g. between {@link #getRangeMinimum()}
+     * and {@link #getRangeMaximum()}).
+     *
+     * @param value the value to display
+     */
+    public final void setValue(int value) {
+        if (mValue != value) {
+            mValue = value;
+
+            updateDisplayedValue();
+        }
+    }
+
+    /**
+     * Returns the currently displayed value.
+     * <p>
+     * If the value is currently being edited, returns the live value which may
+     * not be within the range specified by {@link #setRange(int, int)}.
+     *
+     * @return the currently displayed value
+     */
+    public final int getValue() {
+        return mValue;
+    }
+
+    /**
+     * Sets the valid range (inclusive).
+     *
+     * @param minValue the minimum valid value (inclusive)
+     * @param maxValue the maximum valid value (inclusive)
+     */
+    public final void setRange(int minValue, int maxValue) {
+        if (mMinValue != minValue) {
+            mMinValue = minValue;
+        }
+
+        if (mMaxValue != maxValue) {
+            mMaxValue = maxValue;
+            mMaxCount = 1 + (int) (Math.log(maxValue) / LOG_RADIX);
+
+            updateMinimumWidth();
+            updateDisplayedValue();
+        }
+    }
+
+    /**
+     * @return the minimum value value (inclusive)
+     */
+    public final int getRangeMinimum() {
+        return mMinValue;
+    }
+
+    /**
+     * @return the maximum value value (inclusive)
+     */
+    public final int getRangeMaximum() {
+        return mMaxValue;
+    }
+
+    /**
+     * Sets whether this view shows leading zeroes.
+     * <p>
+     * When leading zeroes are shown, the displayed value will be padded
+     * with zeroes to the width of the maximum value as specified by
+     * {@link #setRange(int, int)} (see also {@link #getRangeMaximum()}.
+     * <p>
+     * For example, with leading zeroes shown, a maximum of 99 and value of
+     * 9 would display "09". A maximum of 100 and a value of 9 would display
+     * "009". With leading zeroes hidden, both cases would show "9".
+     *
+     * @param showLeadingZeroes {@code true} to show leading zeroes,
+     *                          {@code false} to hide them
+     */
+    public final void setShowLeadingZeroes(boolean showLeadingZeroes) {
+        if (mShowLeadingZeroes != showLeadingZeroes) {
+            mShowLeadingZeroes = showLeadingZeroes;
+
+            updateDisplayedValue();
+        }
+    }
+
+    public final boolean getShowLeadingZeroes() {
+        return mShowLeadingZeroes;
+    }
+
+    /**
+     * Computes the display value and updates the text of the view.
+     * <p>
+     * This method should be called whenever the current value or display
+     * properties (leading zeroes, max digits) change.
+     */
+    private void updateDisplayedValue() {
+        final String format;
+        if (mShowLeadingZeroes) {
+            format = "%0" + mMaxCount + "d";
+        } else {
+            format = "%d";
+        }
+
+        // Always use String.format() rather than Integer.toString()
+        // to obtain correctly localized values.
+        setText(String.format(format, mValue));
+    }
+
+    /**
+     * Computes the minimum width in pixels required to display all possible
+     * values and updates the minimum width of the view.
+     * <p>
+     * This method should be called whenever the maximum value changes.
+     */
+    private void updateMinimumWidth() {
+        final CharSequence previousText = getText();
+        int maxWidth = 0;
+
+        for (int i = 0; i < mMaxValue; i++) {
+            setText(String.format("%0" + mMaxCount + "d", i));
+            measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+
+            final int width = getMeasuredWidth();
+            if (width > maxWidth) {
+                maxWidth = width;
+            }
+        }
+
+        setText(previousText);
+        setMinWidth(maxWidth);
+        setMinimumWidth(maxWidth);
+    }
+
+    public final void setOnDigitEnteredListener(OnValueChangedListener listener) {
+        mListener = listener;
+    }
+
+    public final OnValueChangedListener getOnDigitEnteredListener() {
+        return mListener;
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        return isKeyCodeNumeric(keyCode)
+                || (keyCode == KeyEvent.KEYCODE_DEL)
+                || super.onKeyDown(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event) {
+        return isKeyCodeNumeric(keyCode)
+                || (keyCode == KeyEvent.KEYCODE_DEL)
+                || super.onKeyMultiple(keyCode, repeatCount, event);
+    }
+
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        return handleKeyUp(keyCode)
+                || super.onKeyUp(keyCode, event);
+    }
+
+    private boolean handleKeyUp(int keyCode) {
+        if (keyCode == KeyEvent.KEYCODE_DEL) {
+            // Backspace removes the least-significant digit, if available.
+            if (mCount > 0) {
+                mValue /= RADIX;
+                mCount--;
+            }
+        } else if (isKeyCodeNumeric(keyCode)) {
+            if (mCount < mMaxCount) {
+                final int keyValue = numericKeyCodeToInt(keyCode);
+                final int newValue = mValue * RADIX + keyValue;
+                if (newValue <= mMaxValue) {
+                    mValue = newValue;
+                    mCount++;
+                }
+            }
+        } else {
+            return false;
+        }
+
+        final String formattedValue;
+        if (mCount > 0) {
+            // If the user types 01, we should always show the leading 0 even if
+            // getShowLeadingZeroes() is false. Preserve typed leading zeroes by
+            // using the number of digits entered as the format width.
+            formattedValue = String.format("%0" + mCount + "d", mValue);
+        } else {
+            formattedValue = "";
+        }
+
+        setText(formattedValue);
+
+        if (mListener != null) {
+            final boolean isValid = mValue >= mMinValue;
+            final boolean isFinished = mCount >= mMaxCount || mValue * RADIX > mMaxValue;
+            mListener.onValueChanged(this, mValue, isValid, isFinished);
+        }
+
+        return true;
+    }
+
+    private static boolean isKeyCodeNumeric(int keyCode) {
+        return keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1
+                || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3
+                || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5
+                || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7
+                || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9;
+    }
+
+    private static int numericKeyCodeToInt(int keyCode) {
+        return keyCode - KeyEvent.KEYCODE_0;
+    }
+
+    public interface OnValueChangedListener {
+        /**
+         * Called when the value displayed by {@code view} changes.
+         *
+         * @param view the view whose value changed
+         * @param value the new value
+         * @param isValid {@code true} if the value is valid (e.g. within the
+         *                range specified by {@link #setRange(int, int)}),
+         *                {@code false} otherwise
+         * @param isFinished {@code true} if the no more digits may be entered,
+         *                   {@code false} if more digits may be entered
+         */
+        void onValueChanged(NumericTextView view, int value, boolean isValid, boolean isFinished);
+    }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 20d00b0..7b69c9e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -189,6 +189,7 @@
     external/pdfium/core/include/fpdfdoc \
     external/pdfium/fpdfsdk/include \
     external/pdfium/public \
+    external/skia/include/private \
     external/skia/src/core \
     external/skia/src/effects \
     external/skia/src/images \
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 28bc7fe..ecaf951 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -165,7 +165,7 @@
 
     virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) {
         const SkImageInfo& info = bitmap->info();
-        if (info.fColorType == kUnknown_SkColorType) {
+        if (info.colorType() == kUnknown_SkColorType) {
             ALOGW("unable to reuse a bitmap as the target has an unknown bitmap configuration");
             return false;
         }
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 93259e7..068517a 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -486,7 +486,7 @@
 android::Bitmap* GraphicsJNI::allocateJavaPixelRef(JNIEnv* env, SkBitmap* bitmap,
                                              SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
-    if (info.fColorType == kUnknown_SkColorType) {
+    if (info.colorType() == kUnknown_SkColorType) {
         doThrowIAE(env, "unknown bitmap configuration");
         return NULL;
     }
@@ -538,7 +538,7 @@
 
 bool GraphicsJNI::allocatePixels(JNIEnv* env, SkBitmap* bitmap, SkColorTable* ctable) {
     const SkImageInfo& info = bitmap->info();
-    if (info.fColorType == kUnknown_SkColorType) {
+    if (info.colorType() == kUnknown_SkColorType) {
         doThrowIAE(env, "unknown bitmap configuration");
         return NULL;
     }
@@ -581,7 +581,7 @@
     int fd;
 
     const SkImageInfo& info = bitmap->info();
-    if (info.fColorType == kUnknown_SkColorType) {
+    if (info.colorType() == kUnknown_SkColorType) {
         doThrowIAE(env, "unknown bitmap configuration");
         return nullptr;
     }
@@ -625,7 +625,7 @@
 android::Bitmap* GraphicsJNI::mapAshmemPixelRef(JNIEnv* env, SkBitmap* bitmap,
         SkColorTable* ctable, int fd, void* addr, bool readOnly) {
     const SkImageInfo& info = bitmap->info();
-    if (info.fColorType == kUnknown_SkColorType) {
+    if (info.colorType() == kUnknown_SkColorType) {
         doThrowIAE(env, "unknown bitmap configuration");
         return nullptr;
     }
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 6b09450..b50046f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -28,6 +28,7 @@
 #include "SkBlurDrawLooper.h"
 #include "SkColorFilter.h"
 #include "SkMaskFilter.h"
+#include "SkPath.h"
 #include "SkRasterizer.h"
 #include "SkShader.h"
 #include "SkTypeface.h"
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index a14afa0..41aa9ca 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -114,7 +114,7 @@
     return parcel ? parcel->dataCapacity() : 0;
 }
 
-static void android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
+static jlong android_os_Parcel_setDataSize(JNIEnv* env, jclass clazz, jlong nativePtr, jint size)
 {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     if (parcel != NULL) {
@@ -122,7 +122,9 @@
         if (err != NO_ERROR) {
             signalExceptionForError(env, clazz, err);
         }
+        return parcel->getOpenAshmemSize();
     }
+    return 0;
 }
 
 static void android_os_Parcel_setDataPosition(JNIEnv* env, jclass clazz, jlong nativePtr, jint pos)
@@ -304,7 +306,7 @@
     }
 }
 
-static void android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
+static jlong android_os_Parcel_writeFileDescriptor(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
 {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     if (parcel != NULL) {
@@ -313,7 +315,9 @@
         if (err != NO_ERROR) {
             signalExceptionForError(env, clazz, err);
         }
+        return parcel->getOpenAshmemSize();
     }
+    return 0;
 }
 
 static jbyteArray android_os_Parcel_createByteArray(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -546,12 +550,14 @@
     return reinterpret_cast<jlong>(parcel);
 }
 
-static void android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
+static jlong android_os_Parcel_freeBuffer(JNIEnv* env, jclass clazz, jlong nativePtr)
 {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     if (parcel != NULL) {
         parcel->freeData();
+        return parcel->getOpenAshmemSize();
     }
+    return 0;
 }
 
 static void android_os_Parcel_destroy(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -589,12 +595,12 @@
     return ret;
 }
 
-static void android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
-                                         jbyteArray data, jint offset, jint length)
+static jlong android_os_Parcel_unmarshall(JNIEnv* env, jclass clazz, jlong nativePtr,
+                                          jbyteArray data, jint offset, jint length)
 {
     Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
     if (parcel == NULL || length < 0) {
-       return;
+       return 0;
     }
 
     jbyte* array = (jbyte*)env->GetPrimitiveArrayCritical(data, 0);
@@ -608,24 +614,26 @@
 
         env->ReleasePrimitiveArrayCritical(data, array, 0);
     }
+    return parcel->getOpenAshmemSize();
 }
 
-static void android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
-                                         jlong otherNativePtr, jint offset, jint length)
+static jlong android_os_Parcel_appendFrom(JNIEnv* env, jclass clazz, jlong thisNativePtr,
+                                          jlong otherNativePtr, jint offset, jint length)
 {
     Parcel* thisParcel = reinterpret_cast<Parcel*>(thisNativePtr);
     if (thisParcel == NULL) {
-       return;
+       return 0;
     }
     Parcel* otherParcel = reinterpret_cast<Parcel*>(otherNativePtr);
     if (otherParcel == NULL) {
-       return;
+       return thisParcel->getOpenAshmemSize();
     }
 
     status_t err = thisParcel->appendFrom(otherParcel, offset, length);
     if (err != NO_ERROR) {
         signalExceptionForError(env, clazz, err);
     }
+    return thisParcel->getOpenAshmemSize();
 }
 
 static jboolean android_os_Parcel_hasFileDescriptors(JNIEnv* env, jclass clazz, jlong nativePtr)
@@ -718,7 +726,7 @@
     {"nativeDataAvail",           "(J)I", (void*)android_os_Parcel_dataAvail},
     {"nativeDataPosition",        "(J)I", (void*)android_os_Parcel_dataPosition},
     {"nativeDataCapacity",        "(J)I", (void*)android_os_Parcel_dataCapacity},
-    {"nativeSetDataSize",         "(JI)V", (void*)android_os_Parcel_setDataSize},
+    {"nativeSetDataSize",         "(JI)J", (void*)android_os_Parcel_setDataSize},
     {"nativeSetDataPosition",     "(JI)V", (void*)android_os_Parcel_setDataPosition},
     {"nativeSetDataCapacity",     "(JI)V", (void*)android_os_Parcel_setDataCapacity},
 
@@ -733,7 +741,7 @@
     {"nativeWriteDouble",         "(JD)V", (void*)android_os_Parcel_writeDouble},
     {"nativeWriteString",         "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeString},
     {"nativeWriteStrongBinder",   "(JLandroid/os/IBinder;)V", (void*)android_os_Parcel_writeStrongBinder},
-    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)V", (void*)android_os_Parcel_writeFileDescriptor},
+    {"nativeWriteFileDescriptor", "(JLjava/io/FileDescriptor;)J", (void*)android_os_Parcel_writeFileDescriptor},
 
     {"nativeCreateByteArray",     "(J)[B", (void*)android_os_Parcel_createByteArray},
     {"nativeReadBlob",            "(J)[B", (void*)android_os_Parcel_readBlob},
@@ -751,12 +759,12 @@
     {"clearFileDescriptor",       "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
 
     {"nativeCreate",              "()J", (void*)android_os_Parcel_create},
-    {"nativeFreeBuffer",          "(J)V", (void*)android_os_Parcel_freeBuffer},
+    {"nativeFreeBuffer",          "(J)J", (void*)android_os_Parcel_freeBuffer},
     {"nativeDestroy",             "(J)V", (void*)android_os_Parcel_destroy},
 
     {"nativeMarshall",            "(J)[B", (void*)android_os_Parcel_marshall},
-    {"nativeUnmarshall",          "(J[BII)V", (void*)android_os_Parcel_unmarshall},
-    {"nativeAppendFrom",          "(JJII)V", (void*)android_os_Parcel_appendFrom},
+    {"nativeUnmarshall",          "(J[BII)J", (void*)android_os_Parcel_unmarshall},
+    {"nativeAppendFrom",          "(JJII)J", (void*)android_os_Parcel_appendFrom},
     {"nativeHasFileDescriptors",  "(J)Z", (void*)android_os_Parcel_hasFileDescriptors},
     {"nativeWriteInterfaceToken", "(JLjava/lang/String;)V", (void*)android_os_Parcel_writeInterfaceToken},
     {"nativeEnforceInterface",    "(JLjava/lang/String;)V", (void*)android_os_Parcel_enforceInterface},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 24055e7..da96b93 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -313,12 +313,11 @@
         return 0;
     }
 
+
     SkImageInfo info = SkImageInfo::Make(outBuffer.width, outBuffer.height,
                                          convertPixelFormat(outBuffer.format),
-                                         kPremul_SkAlphaType);
-    if (outBuffer.format == PIXEL_FORMAT_RGBX_8888) {
-        info.fAlphaType = kOpaque_SkAlphaType;
-    }
+                                         outBuffer.format == PIXEL_FORMAT_RGBX_8888 ?
+                                         kOpaque_SkAlphaType : kPremul_SkAlphaType);
 
     SkBitmap bitmap;
     ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 65ebb663..931ad54 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -138,35 +138,36 @@
         return NULL;
     }
 
-    SkImageInfo screenshotInfo;
-    screenshotInfo.fWidth = screenshot->getWidth();
-    screenshotInfo.fHeight = screenshot->getHeight();
-
+    SkColorType colorType;
+    SkAlphaType alphaType;
     switch (screenshot->getFormat()) {
         case PIXEL_FORMAT_RGBX_8888: {
-            screenshotInfo.fColorType = kRGBA_8888_SkColorType;
-            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
+            colorType = kRGBA_8888_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
             break;
         }
         case PIXEL_FORMAT_RGBA_8888: {
-            screenshotInfo.fColorType = kRGBA_8888_SkColorType;
-            screenshotInfo.fAlphaType = kPremul_SkAlphaType;
+            colorType = kRGBA_8888_SkColorType;
+            alphaType = kPremul_SkAlphaType;
             break;
         }
         case PIXEL_FORMAT_RGB_565: {
-            screenshotInfo.fColorType = kRGB_565_SkColorType;
-            screenshotInfo.fAlphaType = kOpaque_SkAlphaType;
+            colorType = kRGB_565_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
             break;
         }
         default: {
             return NULL;
         }
     }
+    SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
+                                                   screenshot->getHeight(),
+                                                   colorType, alphaType);
 
     const size_t rowBytes =
             screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());
 
-    if (!screenshotInfo.fWidth || !screenshotInfo.fHeight) {
+    if (!screenshotInfo.width() || !screenshotInfo.height()) {
         return NULL;
     }
 
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index b736a17..e185281 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -72,29 +72,25 @@
 
 // FIXME: consider exporting this to share (e.g. android_view_Surface.cpp)
 static inline SkImageInfo convertPixelFormat(const ANativeWindow_Buffer& buffer) {
-    SkImageInfo info;
-    info.fWidth = buffer.width;
-    info.fHeight = buffer.height;
+    SkColorType colorType = kUnknown_SkColorType;
+    SkAlphaType alphaType = kOpaque_SkAlphaType;
     switch (buffer.format) {
         case WINDOW_FORMAT_RGBA_8888:
-            info.fColorType = kN32_SkColorType;
-            info.fAlphaType = kPremul_SkAlphaType;
+            colorType = kN32_SkColorType;
+            alphaType = kPremul_SkAlphaType;
             break;
         case WINDOW_FORMAT_RGBX_8888:
-            info.fColorType = kN32_SkColorType;
-            info.fAlphaType = kOpaque_SkAlphaType;
+            colorType = kN32_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
             break;
         case WINDOW_FORMAT_RGB_565:
-            info.fColorType = kRGB_565_SkColorType;
-            info.fAlphaType = kOpaque_SkAlphaType;
+            colorType = kRGB_565_SkColorType;
+            alphaType = kOpaque_SkAlphaType;
             break;
         default:
-            info.fColorType = kUnknown_SkColorType;
-            // switch to kUnknown_SkAlphaType when its in skia
-            info.fAlphaType = kOpaque_SkAlphaType;
             break;
     }
-    return info;
+    return SkImageInfo::Make(buffer.width, buffer.height, colorType, alphaType);
 }
 
 /**
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f300741..5828829 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -241,7 +241,6 @@
     <protected-broadcast android:name="android.intent.action.DREAMING_STARTED" />
     <protected-broadcast android:name="android.intent.action.DREAMING_STOPPED" />
     <protected-broadcast android:name="android.intent.action.ANY_DATA_STATE" />
-    <protected-broadcast android:name="android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN" />
 
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
@@ -1477,7 +1476,7 @@
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
         android:label="@string/permlab_systemAlertWindow"
         android:description="@string/permdesc_systemAlertWindow"
-        android:protectionLevel="signature|preinstalled|appop|pre23" />
+        android:protectionLevel="signature|preinstalled|appop|pre23|development" />
 
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
diff --git a/core/res/res/color/primary_text_secondary_when_activated_material_inverse.xml b/core/res/res/color/primary_text_secondary_when_activated_material_inverse.xml
index baa8958..905fd4d 100644
--- a/core/res/res/color/primary_text_secondary_when_activated_material_inverse.xml
+++ b/core/res/res/color/primary_text_secondary_when_activated_material_inverse.xml
@@ -1,8 +1,28 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
+        android:state_enabled="false"
+        android:color="?attr/textColorSecondaryInverse"
+        android:alpha="?attr/disabledAlpha" />
+    <item
         android:state_activated="true"
         android:color="?attr/textColorPrimaryInverse" />
     <item
         android:color="?attr/textColorSecondaryInverse" />
-</selector>
\ No newline at end of file
+</selector>
diff --git a/core/res/res/drawable/time_picker_editable_background.xml b/core/res/res/drawable/time_picker_editable_background.xml
new file mode 100644
index 0000000..72e863b
--- /dev/null
+++ b/core/res/res/drawable/time_picker_editable_background.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_focused="true">
+        <layer-list>
+            <item android:gravity="bottom"
+                  android:height="10dp">
+                <shape android:shape="line"
+                       android:tint="?attr/textColorPrimaryInverse">
+                    <stroke android:color="@color/white"
+                            android:width="2dp" />
+                </shape>
+            </item>
+        </layer-list>
+    </item>
+    <item android:drawable="@color/transparent" />
+</selector>
diff --git a/core/res/res/layout-land/time_picker_material.xml b/core/res/res/layout-land/time_picker_material.xml
index bb347cb..7a0c38f 100644
--- a/core/res/res/layout-land/time_picker_material.xml
+++ b/core/res/res/layout-land/time_picker_material.xml
@@ -51,15 +51,17 @@
 
             <!-- The hour should always be to the left of the separator,
                  regardless of the current locale's layout direction. -->
-            <TextView
+            <com.android.internal.widget.NumericTextView
                 android:id="@+id/hours"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
+                android:background="@drawable/time_picker_editable_background"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:gravity="right"
-                android:includeFontPadding="false" />
+                android:focusable="true"
+                android:nextFocusForward="@+id/minutes" />
 
             <TextView
                 android:id="@+id/separator"
@@ -71,57 +73,56 @@
 
             <!-- The minutes should always be to the right of the separator,
                  regardless of the current locale's layout direction. -->
-            <TextView
+            <com.android.internal.widget.NumericTextView
                 android:id="@+id/minutes"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
+                android:background="@drawable/time_picker_editable_background"
                 android:singleLine="true"
                 android:ellipsize="none"
                 android:gravity="left"
-                android:includeFontPadding="false" />
+                android:focusable="true"
+                android:nextFocusForward="@+id/am_label" />
         </LinearLayout>
 
-        <!-- The layout alignment of this view will switch between toRightOf
-             @id/minutes and toLeftOf @id/hours depending on the locale. -->
-        <LinearLayout
+        <RadioGroup
             android:id="@+id/ampm_layout"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_below="@+id/time_layout"
             android:layout_centerHorizontal="true"
+            android:paddingTop="4dp"
+            android:paddingBottom="4dp"
             android:orientation="vertical"
             android:layoutDirection="locale">
-
-            <CheckedTextView
+            <RadioButton
                 android:id="@+id/am_label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="48dp"
-                android:minWidth="48dp"
-                android:gravity="bottom"
+                android:padding="8dp"
+                android:layout_marginBottom="-8dp"
                 android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingTop="4dp"
-                android:paddingBottom="6dp"
                 android:lines="1"
-                android:ellipsize="none" />
-
-            <CheckedTextView
+                android:ellipsize="none"
+                android:focusable="true"
+                android:background="?android:attr/selectableItemBackground"
+                android:includeFontPadding="false"
+                android:nextFocusForward="@+id/pm_label"
+                android:button="@null" />
+            <RadioButton
                 android:id="@+id/pm_label"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
-                android:minHeight="48dp"
-                android:minWidth="48dp"
-                android:gravity="top"
+                android:padding="8dp"
                 android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
                 android:lines="1"
                 android:ellipsize="none"
-                android:includeFontPadding="false" />
-        </LinearLayout>
+                android:focusable="true"
+                android:background="?android:attr/selectableItemBackground"
+                android:includeFontPadding="false"
+                android:button="@null" />
+        </RadioGroup>
     </RelativeLayout>
 
     <ViewStub
diff --git a/core/res/res/layout/non_client_decor_dark.xml b/core/res/res/layout/non_client_decor_dark.xml
index 112f4b7..40b8960 100644
--- a/core/res/res/layout/non_client_decor_dark.xml
+++ b/core/res/res/layout/non_client_decor_dark.xml
@@ -29,10 +29,11 @@
         android:background="@drawable/non_client_decor_title"
         android:focusable="false"
         android:descendantFocusability="blocksDescendants" >
-        <TextView
+        <LinearLayout
+            android:id="@+id/client_decor_placeholder"
             android:layout_width="0dp"
             android:layout_height="match_parent"
-            android:layout_weight="1" />
+            android:layout_weight="1"/>
         <Button
             android:id="@+id/maximize_window"
             android:layout_width="32dp"
diff --git a/core/res/res/layout/non_client_decor_light.xml b/core/res/res/layout/non_client_decor_light.xml
index 5dd79c7..c75d526 100644
--- a/core/res/res/layout/non_client_decor_light.xml
+++ b/core/res/res/layout/non_client_decor_light.xml
@@ -29,10 +29,11 @@
         android:background="@drawable/non_client_decor_title"
         android:focusable="false"
         android:descendantFocusability="blocksDescendants" >
-        <TextView
+        <LinearLayout
+            android:id="@+id/client_decor_placeholder"
             android:layout_width="0dp"
             android:layout_height="match_parent"
-            android:layout_weight="1" />
+            android:layout_weight="1"/>
         <Button
             android:id="@+id/maximize_window"
             android:layout_width="32dp"
diff --git a/core/res/res/layout/time_picker_header_material.xml b/core/res/res/layout/time_picker_header_material.xml
index acdc509..7019ced 100644
--- a/core/res/res/layout/time_picker_header_material.xml
+++ b/core/res/res/layout/time_picker_header_material.xml
@@ -21,23 +21,24 @@
                 android:id="@+id/time_header"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:orientation="horizontal"
-                android:padding="@dimen/timepicker_separator_padding"
                 android:paddingStart="16dp"
                 android:paddingEnd="16dp">
 
     <!-- The hour should always be to the left of the separator,
          regardless of the current locale's layout direction. -->
-    <TextView
+    <com.android.internal.widget.NumericTextView
         android:id="@+id/hours"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toLeftOf="@+id/separator"
         android:layout_alignBaseline="@+id/separator"
         android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
+        android:background="@drawable/time_picker_editable_background"
         android:singleLine="true"
         android:ellipsize="none"
-        android:gravity="right" />
+        android:gravity="right"
+        android:focusable="true"
+        android:nextFocusForward="@+id/minutes" />
 
     <TextView
         android:id="@+id/separator"
@@ -51,50 +52,57 @@
 
     <!-- The minutes should always be to the left of the separator,
          regardless of the current locale's layout direction. -->
-    <TextView
+    <com.android.internal.widget.NumericTextView
         android:id="@+id/minutes"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@+id/separator"
         android:layout_alignBaseline="@+id/separator"
         android:textAppearance="@style/TextAppearance.Material.TimePicker.TimeLabel"
+        android:background="@drawable/time_picker_editable_background"
         android:singleLine="true"
         android:ellipsize="none"
-        android:gravity="left" />
+        android:gravity="left"
+        android:focusable="true"
+        android:nextFocusForward="@+id/am_label" />
 
     <!-- The layout alignment of this view will switch between toRightOf
          @id/minutes and toLeftOf @id/hours depending on the locale. -->
-    <LinearLayout
+    <RadioGroup
         android:id="@+id/ampm_layout"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_toRightOf="@+id/minutes"
         android:layout_alignBaseline="@+id/minutes"
-        android:paddingStart="8dp"
-        android:paddingEnd="8dp"
+        android:paddingStart="4dp"
+        android:paddingEnd="4dp"
         android:orientation="vertical"
         android:baselineAlignedChildIndex="1">
-        <CheckedTextView
+        <RadioButton
             android:id="@+id/am_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="48dp"
-            android:minHeight="48dp"
-            android:gravity="bottom"
-            android:paddingTop="@dimen/timepicker_am_top_padding"
+            android:padding="8dp"
+            android:layout_marginBottom="-8dp"
             android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
             android:lines="1"
-            android:ellipsize="none" />
-        <CheckedTextView
+            android:ellipsize="none"
+            android:focusable="true"
+            android:background="?android:attr/selectableItemBackground"
+            android:includeFontPadding="false"
+            android:nextFocusForward="@+id/pm_label"
+            android:button="@null" />
+        <RadioButton
             android:id="@+id/pm_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="48dp"
-            android:minHeight="48dp"
-            android:gravity="top"
-            android:paddingTop="@dimen/timepicker_pm_top_padding"
+            android:padding="8dp"
             android:textAppearance="@style/TextAppearance.Material.TimePicker.AmPmLabel"
             android:lines="1"
-            android:ellipsize="none" />
-    </LinearLayout>
+            android:ellipsize="none"
+            android:focusable="true"
+            android:background="?android:attr/selectableItemBackground"
+            android:includeFontPadding="false"
+            android:button="@null" />
+    </RadioGroup>
 </RelativeLayout>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 45e82ac..ff0fa9c 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1029,7 +1029,7 @@
     <string name="adb_active_notification_message" msgid="1016654627626476142">"タップしてUSBデバッグを無効化"</string>
     <string name="select_input_method" msgid="8547250819326693584">"キーボードの変更"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"キーボードの選択"</string>
-    <string name="show_ime" msgid="9157568568695230830">"入力方法を表示する"</string>
+    <string name="show_ime" msgid="9157568568695230830">"スクリーンキーボードを表示する"</string>
     <string name="hardware" msgid="7517821086888990278">"ハードウェア"</string>
     <string name="select_keyboard_layout_notification_title" msgid="1407367017263030773">"キーボードレイアウトの選択"</string>
     <string name="select_keyboard_layout_notification_message" msgid="4465907700449257063">"タップしてキーボードレイアウトを選択してください。"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index 8181f6c..4c1fc88 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -87,7 +87,7 @@
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"कलर ID पूर्वनिर्धारितदेखि प्रतिबन्धित छैन। अर्को कल: प्रतिबन्धित छ"</string>
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"कलर ID पूर्वनिर्धारितको लागि रोकावट छैन। अर्को कल: रोकावट छैन"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"सेवाको व्यवस्था छैन।"</string>
-    <string name="CLIRPermanent" msgid="3377371145926835671">"तपाईं कलर ID सेटिङ परिवर्तन गर्न सक्नुहुन्न।"</string>
+    <string name="CLIRPermanent" msgid="3377371145926835671">"तपाईँ कलर ID सेटिङ परिवर्तन गर्न सक्नुहुन्न।"</string>
     <string name="RestrictedChangedTitle" msgid="5592189398956187498">"प्रतिबन्धित पहुँच परिवर्तन भएको छ"</string>
     <string name="RestrictedOnData" msgid="8653794784690065540">"डेटा सेवा रोकिएको छ।"</string>
     <string name="RestrictedOnEmergency" msgid="6581163779072833665">"आपतकालीन सेवा रोकिएको छ।"</string>
@@ -198,7 +198,7 @@
     <string name="shutdown_confirm" product="tv" msgid="476672373995075359">"तपाईंको TV बन्द हुनेछ।"</string>
     <string name="shutdown_confirm" product="watch" msgid="3490275567476369184">"तपाईँको घडी बन्द गरिने छ।"</string>
     <string name="shutdown_confirm" product="default" msgid="649792175242821353">"तपाईँको फोन बन्द हुने छ।"</string>
-    <string name="shutdown_confirm_question" msgid="2906544768881136183">"के तपाईं बन्द गर्न चाहनुहुन्छ?"</string>
+    <string name="shutdown_confirm_question" msgid="2906544768881136183">"के तपाईँ बन्द गर्न चाहनुहुन्छ?"</string>
     <string name="reboot_safemode_title" msgid="7054509914500140361">"सुरक्षित मोडमा पुनःबुट गर्नुहोस्"</string>
     <string name="reboot_safemode_confirm" msgid="55293944502784668">"सुरक्षित मोडमा तपाईँ पुनःबुट गर्न चाहनु हुन्छ? तपाईँले स्थापना गरेका सबै तेस्रो पक्षका अनुप्रयोगहरूलाई असक्षम गराउने छ।"</string>
     <string name="recent_tasks_title" msgid="3691764623638127888">"नयाँ"</string>
@@ -786,7 +786,7 @@
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"तपाईँको भ्वाइसमेल इनबक्समा सन्देश थप्नको लागि अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"भूस्थान अनुमतिहरू ब्राउजर परिवर्तन गर्नुहोस्"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ब्राउजरको भू-स्थान अनुमतिहरू परिमार्जन गर्न अनुप्रयोगलाई अनुमति दिन्छ। खराब अनुप्रयोगहरूले  स्थान सूचना मनपरी वेब साइटहरूमा पठाउने अनुमतिको लागि यसलाई प्रयोग गर्न सक्छन्।"</string>
-    <string name="save_password_message" msgid="767344687139195790">"के तपाईं ब्राउजरले यो पासवर्ड सम्झेको चाहनुहुन्छ?"</string>
+    <string name="save_password_message" msgid="767344687139195790">"के तपाईँ ब्राउजरले यो पासवर्ड सम्झेको चाहनुहुन्छ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"अहिले होइन"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"सम्झनुहोस्"</string>
     <string name="save_password_never" msgid="8274330296785855105">"कहिल्यै पनि होइन"</string>
@@ -907,13 +907,13 @@
     <string name="aerr_process_silence" msgid="4226685530196000222">"साइलेन्स पुनःबुट नभएसम्म <xliff:g id="PROCESS">%1$s</xliff:g> बाट क्र्यास हुन्छ।"</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
     <string name="anr_activity_application" msgid="1904477189057199066">"<xliff:g id="APPLICATION">%2$s</xliff:g>ले कार्य गरिरहेको छैन।\n\nके तपाईँ यसलाई बन्द गर्न चाहनु हुन्छ?"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"गतिविधि <xliff:g id="ACTIVITY">%1$s</xliff:g> ले प्रतिक्रिया देखाइरहेको छैन।\n\nके तपाईं यसलाई बन्द गर्न चाहनु हुन्छ?"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"गतिविधि <xliff:g id="ACTIVITY">%1$s</xliff:g> ले प्रतिक्रिया देखाइरहेको छैन।\n\nके तपाईँ यसलाई बन्द गर्न चाहनु हुन्छ?"</string>
     <string name="anr_application_process" msgid="8941757607340481057">"<xliff:g id="APPLICATION">%1$s</xliff:g> जवाफ दिइरहेको छैन। के तपाईँ यसलाई बन्द गर्न चाहनु हुन्छ?"</string>
     <string name="anr_process" msgid="6513209874880517125">"प्रक्रिया <xliff:g id="PROCESS">%1$s</xliff:g>ले कार्य गरिरहेको छैन।\n\nके तपाईँ यसलाई बन्द गर्न चाहनु हुन्छ?"</string>
     <string name="force_close" msgid="8346072094521265605">"ठिक छ"</string>
     <string name="report" msgid="4060218260984795706">"रिपोर्ट गर्नुहोस्"</string>
     <string name="wait" msgid="7147118217226317732">"प्रतीक्षा गर्नुहोस्"</string>
-    <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ गैर जिम्मेवारी भएको छ।\n\nके तपाईं यसलाई बन्द गर्न चाहनुहुन्छ?"</string>
+    <string name="webpage_unresponsive" msgid="3272758351138122503">"पृष्ठ गैर जिम्मेवारी भएको छ।\n\nके तपाईँ यसलाई बन्द गर्न चाहनुहुन्छ?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"अनुप्रयोग पुनः निर्देशीत"</string>
     <string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> अहिले चलिरहेको छ।"</string>
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> वास्तविक सुरुवात भएको थियो।"</string>
@@ -1103,7 +1103,7 @@
     <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>
+    <string name="forward_intent_to_owner" msgid="1207197447013960896">"तपाईँ तपाईँको कार्य प्रोफाइल बाहिर यो अनुप्रयोग प्रयोग गरिरहनु भएको छ"</string>
     <string name="forward_intent_to_work" msgid="621480743856004612">"तपाईँ आफ्नो कार्य प्रोफाइलमा यो अनुप्रयोग प्रयोग गरिरहनु भएको छ"</string>
     <string name="input_method_binding_label" msgid="1283557179944992649">"इनपुट विधि"</string>
     <string name="sync_binding_label" msgid="3687969138375092423">"सिङ्क गर्नुहोस्"</string>
@@ -1151,7 +1151,7 @@
     <string name="gpsVerifYes" msgid="2346566072867213563">"हो"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"होइन"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"सीमा नाघेकाहरू मेट्नुहोस्"</string>
-    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"त्यहाँ <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> मेटाइएका आइटमहरू छन् <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>को लागि, खाता <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>। तपाईं के गर्न चाहनु हुन्छ?"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"त्यहाँ <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> मेटाइएका आइटमहरू छन् <xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>को लागि, खाता <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g>। तपाईँ के गर्न चाहनु हुन्छ?"</string>
     <string name="sync_really_delete" msgid="2572600103122596243">"वस्तुहरू मेट्नुहोस्"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"मेटिएकाहरू पूर्ववत बनाउनुहोस्।"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"अहिलेको लागि केही नगर्नुहोस्"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 6c576ad..228f4ae 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -677,7 +677,7 @@
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"Opriți"</string>
     <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Derulaţi"</string>
     <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Derulaţi rapid înainte"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgenţă"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"Numai apeluri de urgență"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Rețea blocată"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"Cardul SIM este blocat cu codul PUK."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Consultaţi Ghidul de utilizare sau contactaţi Serviciul de relaţii cu clienţii."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 49a3862..aac6ba3 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1414,7 +1414,7 @@
     </plurals>
     <string name="restr_pin_try_later" msgid="973144472490532377">"Försök igen senare"</string>
     <string name="immersive_cling_title" msgid="8394201622932303336">"Visar på fullskärm"</string>
-    <string name="immersive_cling_description" msgid="3482371193207536040">"Dra nedåt från skärmens överkant för att avsluta."</string>
+    <string name="immersive_cling_description" msgid="3482371193207536040">"Svep nedåt från skärmens överkant för att avsluta."</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"OK"</string>
     <string name="done_label" msgid="2093726099505892398">"Klart"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"Cirkelreglage för timmar"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7cbf3d2..7a3aab8 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -650,7 +650,7 @@
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Yanlış PIN kodu."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Kilidi açmak için önce Menü\'ye, sonra 0\'a basın."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Acil durum numarası"</string>
-    <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Hizmet yok"</string>
+    <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Servis yok"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ekran kilitli."</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Kilidi açmak veya acil çağrı yapmak için Menü\'ye basın."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Kilidi açmak için Menü\'ye basın."</string>
@@ -1006,14 +1006,14 @@
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"Asla İzin Verme"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"SIM kart çıkarıldı"</string>
     <string name="sim_removed_message" msgid="5450336489923274918">"Hücresel ağ, geçerli bir SIM kart takıp cihazınızı yeniden başlatıncaya kadar kullanılamayacak."</string>
-    <string name="sim_done_button" msgid="827949989369963775">"Tamamlandı"</string>
+    <string name="sim_done_button" msgid="827949989369963775">"Bitti"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"SIM kart eklendi"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"Hücresel ağa erişmek için cihazınızı yeniden başlatın."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"Yeniden başlat"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"Saati ayarlayın"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"Tarihi ayarlayın"</string>
     <string name="date_time_set" msgid="5777075614321087758">"Ayarla"</string>
-    <string name="date_time_done" msgid="2507683751759308828">"Tamamlandı"</string>
+    <string name="date_time_done" msgid="2507683751759308828">"Bitti"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"YENİ: "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"Sağlayan: <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
     <string name="no_permissions" msgid="7283357728219338112">"İzin gerektirmez"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 5ae3e1e..8c0b816 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -650,7 +650,7 @@
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Mã PIN không chính xác."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Để mở khóa, hãy nhấn vào Menu sau đó nhấn 0."</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Số khẩn cấp"</string>
-    <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Không có dịch vụ nào"</string>
+    <string name="lockscreen_carrier_default" msgid="6169005837238288522">"Không có dịch vụ"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Màn hình đã khóa."</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Nhấn vào Menu để mở khóa hoặc thực hiện cuộc gọi khẩn cấp."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Nhấn vào Menu để mở khóa."</string>
diff --git a/core/res/res/values-watch/strings.xml b/core/res/res/values-watch/strings.xml
index e5991fc..dde8b2e 100644
--- a/core/res/res/values-watch/strings.xml
+++ b/core/res/res/values-watch/strings.xml
@@ -26,47 +26,4 @@
 
     <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. Override from base which says "Body Sensors". [CHAR_LIMIT=25] -->
     <string name="permgrouplab_sensors">Sensors</string>
-
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_contactswear">access your contacts</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_locationwear">access this watch\'s location</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_calendarwear">access your calendar</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_smswear">send and view SMS messages</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_storagewear">access photos, media, and files on your watch</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_microphonewear">record audio</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_camerawear">take pictures and record video</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_phonewear">make and manage phone calls</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permgrouplab_sensorswear">access sensor data about your vital signs</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_statusBarServicewear">be the status bar</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_bodySensorswear">access body sensors (like heart rate monitors)</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_accessFineLocationwear">access precise location (GPS and network-based)</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_accessCoarseLocationwear">access approximate location (network-based)</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_sim_communicationwear">send commands to the SIM</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_createNetworkSocketswear">have full network access</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_manageProfileAndDeviceOwnerswear">manage profile and device owners</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_changeWimaxStatewear">change WiMAX state</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_handoverStatuswear">receive Android Beam transfer status</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_route_media_outputwear">route media output</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_readInstallSessionswear">read install sessions</string>
-    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
-    <string name="permlab_requestInstallPackageswear">request install packages</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 602f607..29b729a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -650,8 +650,7 @@
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"PIN码有误。"</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"要解锁,请先按 MENU 再按 0。"</string>
     <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"急救或报警电话"</string>
-    <!-- no translation found for lockscreen_carrier_default (6169005837238288522) -->
-    <skip />
+    <string name="lockscreen_carrier_default" msgid="6169005837238288522">"没有服务"</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"屏幕已锁定。"</string>
     <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"按 Menu 解锁或进行紧急呼救。"</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"按 MENU 解锁。"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 8e36eb0..d7dd3ec 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -323,14 +323,10 @@
         <attr name="windowBackground" format="reference" />
         <!-- Drawable to draw selectively within the inset areas when the windowBackground
              has been set to null. This protects against seeing visual garbage in the
-             surface when the app has not drawn any content into this area. -->
+             surface when the app has not drawn any content into this area. One example is
+             when the user is resizing a window of an activity that has
+             {@link android.R.attr#resizeableActivity} set for multi-window mode. -->
         <attr name="windowBackgroundFallback" format="reference" />
-        <!-- Drawable used to fill in areas the app has not rendered content to yet when the user is
-             resizing the window of an activity that has {@link android.R.attr#resizeableActivity}
-             set for multi-window mode. If unset, the system will try to use windowBackground if
-             set, then windowBackgroundFallback if set. Otherwise, the system default resizing
-             background color -->
-        <attr name="windowResizingBackground" format="reference" />
         <!-- Drawable to use as a frame around the window. -->
         <attr name="windowFrame" format="reference" />
         <!-- Flag indicating whether there should be no title on this window. -->
@@ -1850,7 +1846,6 @@
     <declare-styleable name="Window">
         <attr name="windowBackground" />
         <attr name="windowBackgroundFallback" />
-        <attr name="windowResizingBackground" />
         <attr name="windowContentOverlay" />
         <attr name="windowFrame" />
         <attr name="windowNoTitle" />
@@ -5023,6 +5018,12 @@
         <attr name="autoMirrored" format="boolean" />
     </declare-styleable>
 
+    <!-- Drawable class used to wrap other drawables. -->
+    <declare-styleable name="DrawableWrapper">
+        <!-- The wrapped drawable. -->
+        <attr name="drawable" />
+    </declare-styleable>
+
     <!-- Drawable used to render several states. Each state is represented by
          a child drawable. -->
     <declare-styleable name="StateListDrawable">
@@ -5390,6 +5391,7 @@
         <attr name="color" />
     </declare-styleable>
 
+    <!-- Drawable used to wrap and inset another drawable. -->
     <declare-styleable name="InsetDrawable">
         <attr name="visible" />
         <attr name="drawable" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 322ac4f..07ac471 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1059,7 +1059,7 @@
          at the same time.
 
          <p>The default value is <code>false</code> for applications with
-         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#M} and
+         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#N} and
          <code>true</code> otherwise.
 
          <p>NOTE: A task's root activity value is applied to all additional activities launched in
@@ -1067,11 +1067,24 @@
          all other activities in the task as resizeable and will not if the root activity isn't
          resizeable.
 
-         <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
-         resizeable activities as the system doesn't support fixed orientation on a resizeable
-         activity. -->
+         <p>NOTE: The value of {@link android.R.attr#screenOrientation} is ignored for
+         resizeable activities when in multi-window mode. -->
     <attr name="resizeableActivity" format="boolean" />
 
+    <!-- Indicates that the activity supports the picture-in-picture (PiP) form of multi-window.
+         While it makes sense to be able to resize most activities types in multi-window mode when
+         {@link android.R.attr#resizeableActivity} is set. It only makes sense to put specific types
+         of activities in PiP mode of multi-window. For example, activities that play video. When
+         set the activity will be allowed to enter PiP mode when the system deems it appropriate on
+         devices that support PiP.
+
+         <p>The default value is <code>false</code> for applications with
+         <code>targetSdkVersion</code> lesser than {@link android.os.Build.VERSION_CODES#N} and
+         <code>true</code> otherwise.
+
+         <p>NOTE: Attribute is only used if {@link android.R.attr#resizeableActivity} is true. -->
+    <attr name="supportsPictureInPicture" format="boolean" />
+
     <!-- This value indicates how tasks rooted at this activity will behave in lockTask mode.
          While in lockTask mode the system will not launch non-permitted tasks until
          lockTask mode is disabled.
@@ -1826,6 +1839,7 @@
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
         <attr name="resizeableActivity" />
+        <attr name="supportsPictureInPicture" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
     </declare-styleable>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index d20b09f..400c822 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1249,6 +1249,9 @@
     <!-- Operating volatage for bluetooth controller. 0 by default-->
     <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
 
+    <!-- Whether supported profiles should be reloaded upon enabling bluetooth -->
+    <bool name="config_bluetooth_reload_supported_profiles_when_enabled">false</bool>
+
     <!-- The default data-use polling period. -->
     <integer name="config_datause_polling_period_sec">600</integer>
 
@@ -1285,6 +1288,10 @@
          device is data-only. -->
     <bool name="config_voice_capable">true</bool>
 
+    <!-- Flag indicating that an outbound call must have a call capable phone account
+         that has declared it can process the call's handle. -->
+    <bool name="config_requireCallCapableAccountForHandle">false</bool>
+
     <!-- Flag indicating if the user is notified when the mobile network access is restricted -->
     <bool name="config_user_notification_of_restrictied_mobile_access">true</bool>
 
@@ -2349,9 +2356,6 @@
          is non-interactive. -->
     <bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
 
-    <!-- Default background color to use when resizing a window if the app didn't specify one. -->
-    <integer name="config_windowResizingBackgroundColorARGB">0xFF808080</integer>
-
     <!-- Name of the component to handle network policy notifications. If present,
          disables NetworkPolicyManagerService's presentation of data-usage notifications. -->
     <string translatable="false" name="config_networkPolicyNotificationComponent"></string>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2621bc9c..dd42c22 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -367,7 +367,8 @@
 
     <dimen name="resolver_max_width">480dp</dimen>
 
-    <!-- Size of the offset applied to the position of the circular mask. This
+    <!-- @deprecated Use config_windowOutsetBottom instead.
+         Size of the offset applied to the position of the circular mask. This
          is only used on circular displays. In the case where there is no
          "chin", this will default to 0 -->
     <dimen name="circular_display_mask_offset">0px</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 839e81b..037f1c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2666,6 +2666,7 @@
     <public type="attr" name="initialHeight" />
     <public type="attr" name="minimalSize" />
     <public type="attr" name="resizeableActivity" />
+    <public type="attr" name="supportsPictureInPicture" />
     <public type="attr" name="titleMargin" />
     <public type="attr" name="titleMarginStart" />
     <public type="attr" name="titleMarginEnd" />
@@ -2677,7 +2678,7 @@
     <public type="attr" name="level" />
     <public type="attr" name="contextPopupMenuStyle" />
     <public type="attr" name="textAppearancePopupMenuHeader" />
-    <public type="attr" name="windowResizingBackground" />
+    <public type="attr" name="windowBackgroundFallback" />
 
     <public type="style" name="Theme.Material.DayNight" />
     <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index c8d53d7..7584d4d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -621,7 +621,7 @@
     <string name="permdesc_statusBar">Allows the app to disable the status bar or add and remove system icons.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_statusBarService">status bar</string>
+    <string name="permlab_statusBarService">be the status bar</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_statusBarService">Allows the app to be the status bar.</string>
 
@@ -718,7 +718,7 @@
        discover information about which applications are used on the device.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_manageProfileAndDeviceOwners">Manage profile and device owners</string>
+    <string name="permlab_manageProfileAndDeviceOwners">manage profile and device owners</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to set the profile/device owners.
      [CHAR LIMIT=NONE] -->
     <string name="permdesc_manageProfileAndDeviceOwners">Allows apps to set the profile owners and the device owner.</string>
@@ -882,7 +882,7 @@
         Malicious apps may use this to erase or modify your call log.</string>
 
     <!-- Title of the body sensors permission, listed so the user can decide whether to allow the application to access body sensor data. [CHAR LIMIT=30] -->
-    <string name="permlab_bodySensors">body sensors (like heart rate monitors)
+    <string name="permlab_bodySensors">access body sensors (like heart rate monitors)
     </string>
     <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] -->
     <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors
@@ -936,7 +936,7 @@
         with the operation of the GPS or other location sources.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessFineLocation">precise location (GPS and
+    <string name="permlab_accessFineLocation">access precise location (GPS and
       network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessFineLocation">Allows the app to get your
@@ -947,7 +947,7 @@
       battery power.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_accessCoarseLocation">approximate location
+    <string name="permlab_accessCoarseLocation">access approximate location
       (network-based)</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessCoarseLocation">Allows the app to get your
@@ -970,7 +970,7 @@
       without your confirmation.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_sim_communication">sim communication</string>
+    <string name="permlab_sim_communication">send commands to the SIM</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_sim_communication">Allows the app to send commands to the SIM. This is very dangerous.</string>
 
@@ -1077,7 +1077,7 @@
       connected.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_createNetworkSockets">full network access</string>
+    <string name="permlab_createNetworkSockets">have full network access</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_createNetworkSockets">Allows the app to create
      network sockets and use custom network protocols. The browser and other
@@ -1141,7 +1141,7 @@
      WiMAX is enabled and information about any WiMAX networks that are
      connected. </string>
 
-    <string name="permlab_changeWimaxState">Change WiMAX state</string>
+    <string name="permlab_changeWimaxState">change WiMAX state</string>
     <string name="permdesc_changeWimaxState" product="tablet">Allows the app to
       connect the tablet to and disconnect the tablet from WiMAX networks.</string>
     <string name="permdesc_changeWimaxState" product="tv">Allows the app to
@@ -1346,7 +1346,7 @@
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_accessDrmCertificates">Allows an application to provision and use DRM certficates. Should never be needed for normal apps.</string>
 
-    <string name="permlab_handoverStatus">Receive Android Beam transfer status</string>
+    <string name="permlab_handoverStatus">receive Android Beam transfer status</string>
     <string name="permdesc_handoverStatus">Allows this application to receive information about current Android Beam transfers</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
@@ -2975,17 +2975,17 @@
     <string name="activity_list_empty">No matching activities found.</string>
 
     <!-- Title of an application permission that lets an application route media output. -->
-    <string name="permlab_route_media_output">Route media output</string>
+    <string name="permlab_route_media_output">route media output</string>
     <!-- Description of an application permission that lets an application route media output. -->
     <string name="permdesc_route_media_output">Allows an application to route media output to other external devices.</string>
 
     <!-- Title of an application permission that lets it read install sessions. -->
-    <string name="permlab_readInstallSessions">Read install sessions</string>
+    <string name="permlab_readInstallSessions">read install sessions</string>
     <!-- Description of an application permission that lets it read install sessions. -->
     <string name="permdesc_readInstallSessions">Allows an application to read install sessions. This allows it to see details about active package installations.</string>
 
     <!-- Title of an application permission that lets it read install sessions. -->
-    <string name="permlab_requestInstallPackages">Request install packages</string>
+    <string name="permlab_requestInstallPackages">request install packages</string>
     <!-- Description of an application permission that lets it read install sessions. -->
     <string name="permdesc_requestInstallPackages">Allows an application to request installation of packages.</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6f239e6..d1932fc 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -275,6 +275,7 @@
   <java-symbol type="bool" name="config_ui_enableFadingMarquee" />
   <java-symbol type="bool" name="config_use_strict_phone_number_comparation" />
   <java-symbol type="bool" name="config_voice_capable" />
+  <java-symbol type="bool" name="config_requireCallCapableAccountForHandle" />
   <java-symbol type="bool" name="config_user_notification_of_restrictied_mobile_access" />
   <java-symbol type="bool" name="config_wifiDisplaySupportsProtectedBuffers" />
   <java-symbol type="bool" name="preferences_prefer_dual_pane" />
@@ -370,6 +371,7 @@
   <java-symbol type="integer" name="config_bluetooth_rx_cur_ma" />
   <java-symbol type="integer" name="config_bluetooth_tx_cur_ma" />
   <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
+  <java-symbol type="bool" name="config_bluetooth_reload_supported_profiles_when_enabled" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
   <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
@@ -1954,6 +1956,7 @@
   <java-symbol type="bool" name="config_built_in_sip_phone" />
   <java-symbol type="id" name="maximize_window" />
   <java-symbol type="id" name="close_window" />
+  <java-symbol type="id" name="client_decor_placeholder" />
   <java-symbol type="layout" name="non_client_decor_light" />
   <java-symbol type="layout" name="non_client_decor_dark" />
   <java-symbol type="drawable" name="non_client_decor_title_focused" />
@@ -2332,7 +2335,5 @@
 
   <java-symbol type="string" name="config_iccHotswapPromptForRestartDialogComponent" />
 
-  <java-symbol type="integer" name="config_windowResizingBackgroundColorARGB" />
-
   <java-symbol type="string" name="config_packagedKeyboardName" />
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
index 80181cf..4c9b00a 100644
--- a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -20,6 +20,7 @@
 import android.content.Intent;
 import android.os.UserHandle;
 import android.test.AndroidTestCase;
+import android.view.inputmethod.InputMethodInfo;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -77,6 +78,27 @@
         assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
     }
 
+    public void testQueryAppsDefaultIme() {
+        // Test query default system IMEs
+        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES,
+                true, UserHandle.of(UserHandle.myUserId()));
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);
+
+        // Test query default IMEs
+        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
+                UserHandle.of(UserHandle.myUserId()));
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "app4"), apps);
+
+        // Test that GET_DEFAULT_IMES cannot be used with a user id different from current process
+        try {
+            mAppsQueryHelper.queryApps(AppsQueryHelper.GET_DEFAULT_IMES, false,
+                    UserHandle.of(UserHandle.USER_NULL));
+            fail("queryApps must fail if wrong user was passed");
+        } catch (IllegalArgumentException e) {
+            // OK
+        }
+    }
+
     private class AppsQueryHelperTestable extends AppsQueryHelper {
 
         public AppsQueryHelperTestable(Context context) {
@@ -121,6 +143,21 @@
             p1.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
             return Arrays.asList(p1);
         }
+
+        @Override
+        protected List<InputMethodInfo> getInputMethodList() {
+            final ResolveInfo sysApp1 = new ResolveInfo();
+            sysApp1.serviceInfo = new ServiceInfo();
+            sysApp1.serviceInfo.packageName = "sys_app1";
+            sysApp1.serviceInfo.name = "name";
+            InputMethodInfo imi1 = new InputMethodInfo(sysApp1, false, null, null, 0, true);
+            final ResolveInfo app4 = new ResolveInfo();
+            app4.serviceInfo = new ServiceInfo();
+            app4.serviceInfo.packageName = "app4";
+            app4.serviceInfo.name = "name";
+            InputMethodInfo imi2 = new InputMethodInfo(app4, false, null, null, 0, true);
+            return Arrays.asList(imi1, imi2);
+        }
     }
 
     private static void assertEqualsIgnoreOrder(List<String> expected, List<String> actual) {
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index b6b4f4f..d5f6321 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -561,9 +561,13 @@
         assertTrue(v46lp.isProvisioned());
 
         assertEquals(ProvisioningChange.STILL_PROVISIONED,
+                LinkProperties.compareProvisioning(v4lp, v46lp));
+        assertEquals(ProvisioningChange.STILL_PROVISIONED,
                 LinkProperties.compareProvisioning(v6lp, v46lp));
         assertEquals(ProvisioningChange.LOST_PROVISIONING,
                 LinkProperties.compareProvisioning(v46lp, v6lp));
+        assertEquals(ProvisioningChange.LOST_PROVISIONING,
+                LinkProperties.compareProvisioning(v46lp, v4lp));
 
         // Check that losing and gaining a secondary router does not change
         // the provisioning status.
diff --git a/core/tests/coretests/src/android/util/TimeUtilsTest.java b/core/tests/coretests/src/android/util/TimeUtilsTest.java
index 74c8e04..2370627 100644
--- a/core/tests/coretests/src/android/util/TimeUtilsTest.java
+++ b/core/tests/coretests/src/android/util/TimeUtilsTest.java
@@ -436,15 +436,17 @@
         assertFormatDuration("+100ms", 100);
         assertFormatDuration("+101ms", 101);
         assertFormatDuration("+330ms", 330);
+        assertFormatDuration("+1s0ms", 1000);
         assertFormatDuration("+1s330ms", 1330);
         assertFormatDuration("+10s24ms", 10024);
+        assertFormatDuration("+1m0s30ms", 60030);
+        assertFormatDuration("+1h0m0s30ms", 3600030);
+        assertFormatDuration("+1d0h0m0s30ms", 86400030);
     }
 
     public void testFormatHugeDuration() {
-        //assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
-        // TODO: improve formatDuration() API
-        assertFormatDuration("+999d23h59m59s999ms", 1342833071555L);
-        assertFormatDuration("-999d23h59m59s999ms", -1342833071555L);
+        assertFormatDuration("+15542d1h11m11s555ms", 1342833071555L);
+        assertFormatDuration("-15542d1h11m11s555ms", -1342833071555L);
     }
 
     private void assertFormatDuration(String expected, long duration) {
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
new file mode 100644
index 0000000..c5e2ae6
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/TextViewActivityMouseTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget;
+
+import static android.widget.espresso.TextViewActions.mouseDragOnText;
+import static android.widget.espresso.TextViewAssertions.hasSelection;
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.action.ViewActions.typeTextIntoFocusedView;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+
+import com.android.frameworks.coretests.R;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests mouse interaction of the TextView widget from an Activity
+ */
+public class TextViewActivityMouseTest extends ActivityInstrumentationTestCase2<TextViewActivity>{
+
+    public TextViewActivityMouseTest() {
+        super(TextViewActivity.class);
+    }
+
+    @SmallTest
+    public void testSelectTextByDrag() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello world!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText(helloWorld.indexOf("llo"), helloWorld.indexOf("ld!")));
+
+        onView(withId(R.id.textview)).check(hasSelection("llo wor"));
+    }
+
+    @SmallTest
+    public void testSelectTextByDrag_reverse() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello world!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                mouseDragOnText( helloWorld.indexOf("ld!"), helloWorld.indexOf("llo")));
+
+        onView(withId(R.id.textview)).check(hasSelection("llo wor"));
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
index a0cd848..9ff8e82 100644
--- a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
@@ -20,25 +20,22 @@
 import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static org.hamcrest.Matchers.allOf;
-
 import android.annotation.Nullable;
 import android.os.SystemClock;
 import android.support.test.espresso.UiController;
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
-import android.support.test.espresso.action.GeneralClickAction;
 import android.support.test.espresso.action.MotionEvents;
 import android.support.test.espresso.action.PrecisionDescriber;
-import android.support.test.espresso.action.Press;
 import android.support.test.espresso.action.Swiper;
-import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.widget.TextView;
+
 import org.hamcrest.Matcher;
 
 
@@ -51,11 +48,48 @@
  * <ul>
  */
 public final class DragOnTextViewActions implements ViewAction {
+    public interface Dragger extends Swiper {
+        UiController wrapUiController(UiController uiController);
+    }
 
     /**
      * Executes different "drag on text" types to given positions.
      */
-    public enum Drag implements Swiper {
+    public enum Drag implements Dragger {
+
+        /**
+         * Starts a drag with a mouse down.
+         */
+        MOUSE_DOWN {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                public MotionEvent perform(
+                        UiController uiController, float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    return downEvent;
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "mouse down and drag to select";
+            }
+
+            @Override
+            public UiController wrapUiController(UiController uiController) {
+                return new MouseUiController(uiController);
+            }
+        },
 
         /**
          * Starts a drag with a long-press.
@@ -197,6 +231,11 @@
 
             return res;
         }
+
+        @Override
+        public UiController wrapUiController(UiController uiController) {
+            return uiController;
+        }
     }
 
     /**
@@ -215,13 +254,13 @@
         MotionEvent perform(UiController uiController, float[] coordinates, float[] precision);
     }
 
-    private final Swiper mDragger;
+    private final Dragger mDragger;
     private final CoordinatesProvider mStartCoordinatesProvider;
     private final CoordinatesProvider mEndCoordinatesProvider;
     private final PrecisionDescriber mPrecisionDescriber;
 
     public DragOnTextViewActions(
-            Swiper dragger,
+            Dragger dragger,
             CoordinatesProvider startCoordinatesProvider,
             CoordinatesProvider endCoordinatesProvider,
             PrecisionDescriber precisionDescriber) {
@@ -242,6 +281,8 @@
         checkNotNull(uiController);
         checkNotNull(view);
 
+        uiController = mDragger.wrapUiController(uiController);
+
         float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view);
         float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view);
         float[] precision = mPrecisionDescriber.describePrecision();
diff --git a/core/tests/coretests/src/android/widget/espresso/MouseUiController.java b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
new file mode 100644
index 0000000..f1387f8
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/MouseUiController.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.widget.espresso;
+
+import android.support.test.espresso.InjectEventSecurityException;
+import android.support.test.espresso.UiController;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * Class to wrap an UiController to overwrite source of motion events to SOURCE_MOUSE.
+ * Note that this doesn't change the tool type.
+ */
+public class MouseUiController implements UiController {
+    private final UiController mUiController;
+
+    public MouseUiController(UiController uiController) {
+        mUiController = uiController;
+    }
+
+    @Override
+    public boolean injectKeyEvent(KeyEvent event) throws InjectEventSecurityException {
+        return mUiController.injectKeyEvent(event);
+    }
+
+    @Override
+    public boolean injectMotionEvent(MotionEvent event) throws InjectEventSecurityException {
+        // Modify the event to mimic mouse primary button event.
+        event.setSource(InputDevice.SOURCE_MOUSE);
+        event.setButtonState(MotionEvent.BUTTON_PRIMARY);
+        return mUiController.injectMotionEvent(event);
+    }
+
+    @Override
+    public boolean injectString(String str) throws InjectEventSecurityException {
+        return mUiController.injectString(str);
+    }
+
+    @Override
+    public void loopMainThreadForAtLeast(long millisDelay) {
+        mUiController.loopMainThreadForAtLeast(millisDelay);
+    }
+
+    @Override
+    public void loopMainThreadUntilIdle() {
+        mUiController.loopMainThreadUntilIdle();
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 835b1b9..4f5a72b 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -124,6 +124,27 @@
     }
 
     /**
+     * Returns an action that click then drags by mouse on text from startIndex to endIndex on the
+     * TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction mouseDragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragOnTextViewActions(
+                        DragOnTextViewActions.Drag.MOUSE_DOWN,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.PINPOINT));
+    }
+
+    /**
      * A provider of the x, y coordinates of the text at the specified index in a text view.
      */
     private static final class TextCoordinates implements CoordinatesProvider {
diff --git a/graphics/java/android/graphics/Point.java b/graphics/java/android/graphics/Point.java
index 3bd17fa..abcccbd 100644
--- a/graphics/java/android/graphics/Point.java
+++ b/graphics/java/android/graphics/Point.java
@@ -99,7 +99,7 @@
 
     /** @hide */
     public void printShortString(PrintWriter pw) {
-        pw.println("["); pw.print(x); pw.print(","); pw.print(y); pw.print("]");
+        pw.print("["); pw.print(x); pw.print(","); pw.print(y); pw.print("]");
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index 4fc5ede..971a3a2 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -50,7 +50,7 @@
      * Creates a new animated rotating drawable with no wrapped drawable.
      */
     public AnimatedRotateDrawable() {
-        this(new AnimatedRotateState(null), null);
+        this(new AnimatedRotateState(null, null), null);
     }
 
     @Override
@@ -126,58 +126,22 @@
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
-        super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
+
+        // Inflation will advance the XmlPullParser and AttributeSet.
+        super.inflate(r, parser, attrs, theme);
 
         updateStateFromTypedArray(a);
-        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
 
         updateLocalState();
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
-        // If we're not waiting on a theme, verify required attributes.
-        if (getDrawable() == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
-    }
-
     @Override
-    void updateStateFromTypedArray(TypedArray a) {
-        super.updateStateFromTypedArray(a);
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
 
         final AnimatedRotateState state = mState;
-
-        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
-            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
-            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
-            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        }
-
-        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotY)) {
-            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
-            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
-            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-        }
-
-        setFramesCount(a.getInt(
-                R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount));
-        setFramesDuration(a.getInt(
-                R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration));
-
-        final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);
-        if (dr != null) {
-            setDrawable(dr);
-        }
-    }
-
-    @Override
-    public void applyTheme(@Nullable Theme t) {
-        final AnimatedRotateState state = mState;
         if (state == null) {
             return;
         }
@@ -195,13 +159,49 @@
             }
         }
 
-        // The drawable may have changed as a result of applying the theme, so
-        // apply the theme to the wrapped drawable last.
-        super.applyTheme(t);
-
         updateLocalState();
     }
 
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
+        final AnimatedRotateState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
+            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
+            state.mPivotXRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotX = state.mPivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotY)) {
+            final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
+            state.mPivotYRel = tv.type == TypedValue.TYPE_FRACTION;
+            state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
+        }
+
+        setFramesCount(a.getInt(
+                R.styleable.AnimatedRotateDrawable_framesCount, state.mFramesCount));
+        setFramesDuration(a.getInt(
+                R.styleable.AnimatedRotateDrawable_frameDuration, state.mFrameDuration));
+    }
+
     public void setFramesCount(int framesCount) {
         mState.mFramesCount = framesCount;
         mIncrement = 360.0f / mState.mFramesCount;
@@ -211,7 +211,15 @@
         mState.mFrameDuration = framesDuration;
     }
 
+    @Override
+    DrawableWrapperState mutateConstantState() {
+        mState = new AnimatedRotateState(mState, null);
+        return mState;
+    }
+
     static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {
+        private int[] mThemeAttrs;
+
         boolean mPivotXRel = false;
         float mPivotX = 0;
         boolean mPivotYRel = false;
@@ -219,8 +227,8 @@
         int mFrameDuration = 150;
         int mFramesCount = 12;
 
-        public AnimatedRotateState(AnimatedRotateState orig) {
-            super(orig);
+        public AnimatedRotateState(AnimatedRotateState orig, Resources res) {
+            super(orig, res);
 
             if (orig != null) {
                 mPivotXRel = orig.mPivotXRel;
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 31fccd0..cdd336d 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -21,6 +21,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
@@ -59,7 +61,7 @@
     private ClipState mState;
 
     ClipDrawable() {
-        this(new ClipState(null), null);
+        this(new ClipState(null, null), null);
     }
 
     /**
@@ -72,7 +74,7 @@
      *                   {@link #VERTICAL}
      */
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
-        this(new ClipState(null), null);
+        this(new ClipState(null, null), null);
 
         mState.mGravity = gravity;
         mState.mOrientation = orientation;
@@ -81,46 +83,24 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
+
+        // Inflation will advance the XmlPullParser and AttributeSet.
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
         updateStateFromTypedArray(a);
-        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
-        // If we're not waiting on a theme, verify required attributes.
-        if (getDrawable() == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <clip> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
-    }
-
     @Override
-    void updateStateFromTypedArray(TypedArray a) {
-        super.updateStateFromTypedArray(a);
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
 
         final ClipState state = mState;
-        state.mOrientation = a.getInt(
-                R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
-        state.mGravity = a.getInt(
-                R.styleable.ClipDrawable_gravity, state.mGravity);
-
-        final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);
-        if (dr != null) {
-            setDrawable(dr);
-        }
-    }
-
-    @Override
-    public void applyTheme(Theme t) {
-        final ClipState state = mState;
         if (state == null) {
             return;
         }
@@ -136,10 +116,34 @@
                 a.recycle();
             }
         }
+    }
 
-        // The drawable may have changed as a result of applying the theme, so
-        // apply the theme to the wrapped drawable last.
-        super.applyTheme(t);
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <clip> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
+        final ClipState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        state.mOrientation = a.getInt(
+                R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
+        state.mGravity = a.getInt(
+                R.styleable.ClipDrawable_gravity, state.mGravity);
     }
 
     @Override
@@ -200,12 +204,20 @@
         }
     }
 
+    @Override
+    DrawableWrapperState mutateConstantState() {
+        mState = new ClipState(mState, null);
+        return mState;
+    }
+
     static final class ClipState extends DrawableWrapper.DrawableWrapperState {
+        private int[] mThemeAttrs;
+
         int mOrientation = HORIZONTAL;
         int mGravity = Gravity.LEFT;
 
-        ClipState(ClipState orig) {
-            super(orig);
+        ClipState(ClipState orig, Resources res) {
+            super(orig, res);
 
             if (orig != null) {
                 mOrientation = orig.mOrientation;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b95c183..ff28777 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -55,6 +55,8 @@
 import java.util.Arrays;
 import java.util.Collection;
 
+import com.android.internal.R;
+
 /**
  * A Drawable is a general abstraction for "something that can be drawn."  Most
  * often you will deal with Drawable as the type of resource retrieved for
@@ -791,8 +793,10 @@
 
     /**
      * Applies the specified theme to this Drawable and its children.
+     *
+     * @param t the theme to apply
      */
-    public void applyTheme(@SuppressWarnings("unused") Theme t) {
+    public void applyTheme(@NonNull @SuppressWarnings("unused") Theme t) {
     }
 
     public boolean canApplyTheme() {
@@ -1177,8 +1181,8 @@
      *
      * @see #inflate(Resources, XmlPullParser, AttributeSet, Theme)
      */
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs)
-            throws XmlPullParserException, IOException {
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs) throws XmlPullParserException, IOException {
         inflate(r, parser, attrs, null);
     }
 
@@ -1192,17 +1196,11 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a;
-        if (theme != null) {
-            a = theme.obtainStyledAttributes(
-                    attrs, com.android.internal.R.styleable.Drawable, 0, 0);
-        } else {
-            a = r.obtainAttributes(attrs, com.android.internal.R.styleable.Drawable);
-        }
-
-        inflateWithAttributes(r, parser, a, com.android.internal.R.styleable.Drawable_visible);
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.Drawable);
+        mVisible = a.getBoolean(R.styleable.Drawable_visible, mVisible);
         a.recycle();
     }
 
@@ -1212,8 +1210,8 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr)
-            throws XmlPullParserException, IOException {
+    void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException {
         mVisible = attrs.getBoolean(visibleAttr, mVisible);
     }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 9185e1a..c427870 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -16,6 +16,8 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -23,6 +25,7 @@
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -33,6 +36,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.view.View;
 
 import java.io.IOException;
@@ -112,7 +116,66 @@
         return mDrawable;
     }
 
-    void updateStateFromTypedArray(TypedArray a) {
+    @Override
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        super.inflate(r, parser, attrs, theme);
+
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // The density may have changed since the last update. This will
+        // apply scaling to any existing constant state properties.
+        final int densityDpi = r.getDisplayMetrics().densityDpi;
+        final int targetDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+        state.setDensity(targetDensity);
+
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.DrawableWrapper);
+        updateStateFromTypedArray(a);
+        a.recycle();
+
+        inflateChildDrawable(r, parser, attrs, theme);
+    }
+
+    @Override
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
+
+        // If we load the drawable later as part of updating from the typed
+        // array, it will already be themed correctly. So, we can theme the
+        // local drawable first.
+        if (mDrawable != null && mDrawable.canApplyTheme()) {
+            mDrawable.applyTheme(t);
+        }
+
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        final int densityDpi = t.getResources().getDisplayMetrics().densityDpi;
+        final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+        state.setDensity(density);
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.DrawableWrapper);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+    }
+
+    /**
+     * Updates constant state properties from the provided typed array.
+     * <p>
+     * Implementing subclasses should call through to the super method first.
+     *
+     * @param a the typed array rom which properties should be read
+     */
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
         final DrawableWrapperState state = mState;
         if (state == null) {
             return;
@@ -124,20 +187,8 @@
         // Extract the theme attributes, if any.
         state.mThemeAttrs = a.extractThemeAttrs();
 
-        // TODO: Consider using R.styleable.DrawableWrapper_drawable
-    }
-
-    @Override
-    public void applyTheme(Resources.Theme t) {
-        super.applyTheme(t);
-
-        final DrawableWrapperState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (mDrawable != null && mDrawable.canApplyTheme()) {
-            mDrawable.applyTheme(t);
+        if (a.hasValueOrEmpty(R.styleable.DrawableWrapper_drawable)) {
+            setDrawable(a.getDrawable(R.styleable.DrawableWrapper_drawable));
         }
     }
 
@@ -371,8 +422,9 @@
      * child element will take precedence over any other child elements or
      * explicit drawable attribute.
      */
-    void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Resources.Theme theme) throws XmlPullParserException, IOException {
+    private void inflateChildDrawable(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
         // Seek to the first child element.
         Drawable dr = null;
         int type;
@@ -390,17 +442,61 @@
     }
 
     abstract static class DrawableWrapperState extends Drawable.ConstantState {
-        int[] mThemeAttrs;
+        private int[] mThemeAttrs;
+
         int mChangingConfigurations;
+        int mDensity = DisplayMetrics.DENSITY_DEFAULT;
 
         Drawable.ConstantState mDrawableState;
 
-        DrawableWrapperState(DrawableWrapperState orig) {
+        DrawableWrapperState(@Nullable DrawableWrapperState orig, @Nullable Resources res) {
             if (orig != null) {
                 mThemeAttrs = orig.mThemeAttrs;
                 mChangingConfigurations = orig.mChangingConfigurations;
                 mDrawableState = orig.mDrawableState;
             }
+
+            final int density;
+            if (res != null) {
+                density = res.getDisplayMetrics().densityDpi;
+            } else if (orig != null) {
+                density = orig.mDensity;
+            } else {
+                density = 0;
+            }
+
+            mDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density;
+        }
+
+        /**
+         * Sets the constant state density.
+         * <p>
+         * If the density has been previously set, dispatches the change to
+         * subclasses so that density-dependent properties may be scaled as
+         * necessary.
+         *
+         * @param targetDensity the new constant state density
+         */
+        public final void setDensity(int targetDensity) {
+            if (mDensity != targetDensity) {
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
+
+                onDensityChanged(sourceDensity, targetDensity);
+            }
+        }
+
+        /**
+         * Called when the constant state density changes.
+         * <p>
+         * Subclasses with density-dependent constant state properties should
+         * override this method and scale their properties as necessary.
+         *
+         * @param sourceDensity the previous constant state density
+         * @param targetDensity the new constant state density
+         */
+        void onDensityChanged(int sourceDensity, int targetDensity) {
+            // Stub method.
         }
 
         @Override
@@ -425,7 +521,7 @@
         }
 
         @Override
-        public abstract Drawable newDrawable(Resources res);
+        public abstract Drawable newDrawable(@Nullable Resources res);
 
         @Override
         public int getChangingConfigurations() {
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index e1ebdbb..927b9c9 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -22,14 +22,17 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.Bitmap;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 
 import java.io.IOException;
 
@@ -58,7 +61,7 @@
      * No-arg constructor used by drawable inflation.
      */
     InsetDrawable() {
-        this(new InsetState(null), null);
+        this(new InsetState(null, null), null);
     }
 
     /**
@@ -67,7 +70,7 @@
      * @param drawable The drawable to inset.
      * @param inset Inset in pixels around the drawable.
      */
-    public InsetDrawable(Drawable drawable, int inset) {
+    public InsetDrawable(@Nullable Drawable drawable, int inset) {
         this(drawable, inset, inset, inset, inset);
     }
 
@@ -80,9 +83,9 @@
      * @param insetRight Right inset in pixels.
      * @param insetBottom Bottom inset in pixels.
      */
-    public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,int insetRight,
-            int insetBottom) {
-        this(new InsetState(null), null);
+    public InsetDrawable(@Nullable Drawable drawable, int insetLeft, int insetTop,
+            int insetRight, int insetBottom) {
+        this(new InsetState(null, null), null);
 
         mState.mInsetLeft = insetLeft;
         mState.mInsetTop = insetTop;
@@ -93,70 +96,24 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
+
+        // Inflation will advance the XmlPullParser and AttributeSet.
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
         updateStateFromTypedArray(a);
-        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
-        // If we're not waiting on a theme, verify required attributes.
-        if (getDrawable() == null && (mState.mThemeAttrs == null
-                || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <inset> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
-    }
-
     @Override
-    void updateStateFromTypedArray(TypedArray a) {
-        super.updateStateFromTypedArray(a);
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
 
         final InsetState state = mState;
-        final int N = a.getIndexCount();
-        for (int i = 0; i < N; i++) {
-            final int attr = a.getIndex(i);
-            switch (attr) {
-                case R.styleable.InsetDrawable_drawable:
-                    final Drawable dr = a.getDrawable(attr);
-                    if (dr != null) {
-                        setDrawable(dr);
-                    }
-                    break;
-                case R.styleable.InsetDrawable_inset:
-                    final int inset = a.getDimensionPixelOffset(attr, Integer.MIN_VALUE);
-                    if (inset != Integer.MIN_VALUE) {
-                        state.mInsetLeft = inset;
-                        state.mInsetTop = inset;
-                        state.mInsetRight = inset;
-                        state.mInsetBottom = inset;
-                    }
-                    break;
-                case R.styleable.InsetDrawable_insetLeft:
-                    state.mInsetLeft = a.getDimensionPixelOffset(attr, state.mInsetLeft);
-                    break;
-                case R.styleable.InsetDrawable_insetTop:
-                    state.mInsetTop = a.getDimensionPixelOffset(attr, state.mInsetTop);
-                    break;
-                case R.styleable.InsetDrawable_insetRight:
-                    state.mInsetRight = a.getDimensionPixelOffset(attr, state.mInsetRight);
-                    break;
-                case R.styleable.InsetDrawable_insetBottom:
-                    state.mInsetBottom = a.getDimensionPixelOffset(attr, state.mInsetBottom);
-                    break;
-            }
-        }
-    }
-
-    @Override
-    public void applyTheme(Theme t) {
-        final InsetState state = mState;
         if (state == null) {
             return;
         }
@@ -172,10 +129,47 @@
                 a.recycle();
             }
         }
+    }
 
-        // The drawable may have changed as a result of applying the theme, so
-        // apply the theme to the wrapped drawable last.
-        super.applyTheme(t);
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <inset> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
+        final InsetState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        // Inset attribute may be overridden by more specific attributes.
+        if (a.hasValue(R.styleable.InsetDrawable_inset)) {
+            final int inset = a.getDimensionPixelOffset(R.styleable.InsetDrawable_inset, 0);
+            state.mInsetLeft = inset;
+            state.mInsetTop = inset;
+            state.mInsetRight = inset;
+            state.mInsetBottom = inset;
+        }
+
+        state.mInsetLeft = a.getDimensionPixelOffset(
+                R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
+        state.mInsetRight = a.getDimensionPixelOffset(
+                R.styleable.InsetDrawable_insetRight, state.mInsetRight);
+        state.mInsetTop = a.getDimensionPixelOffset(
+                R.styleable.InsetDrawable_insetTop, state.mInsetTop);
+        state.mInsetBottom = a.getDimensionPixelOffset(
+                R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
     }
 
     @Override
@@ -243,30 +237,72 @@
 
     @Override
     DrawableWrapperState mutateConstantState() {
-        mState = new InsetState(mState);
+        mState = new InsetState(mState, null);
         return mState;
     }
 
     static final class InsetState extends DrawableWrapper.DrawableWrapperState {
+        private int[] mThemeAttrs;
+
         int mInsetLeft = 0;
         int mInsetTop = 0;
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        InsetState(InsetState orig) {
-            super(orig);
+        InsetState(@Nullable InsetState orig, @Nullable Resources res) {
+            super(orig, res);
 
             if (orig != null) {
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
                 mInsetRight = orig.mInsetRight;
                 mInsetBottom = orig.mInsetBottom;
+
+                if (orig.mDensity != mDensity) {
+                    applyDensityScaling(orig.mDensity, mDensity);
+                }
             }
         }
 
         @Override
-        public Drawable newDrawable(Resources res) {
-            return new InsetDrawable(this, res);
+        void onDensityChanged(int sourceDensity, int targetDensity) {
+            super.onDensityChanged(sourceDensity, targetDensity);
+
+            applyDensityScaling(sourceDensity, targetDensity);
+        }
+
+        /**
+         * Called when the constant state density changes to scale
+         * density-dependent properties specific to insets.
+         *
+         * @param sourceDensity the previous constant state density
+         * @param targetDensity the new constant state density
+         */
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            mInsetLeft = Bitmap.scaleFromDensity(mInsetLeft, sourceDensity, targetDensity);
+            mInsetTop = Bitmap.scaleFromDensity(mInsetTop, sourceDensity, targetDensity);
+            mInsetRight = Bitmap.scaleFromDensity(mInsetRight, sourceDensity, targetDensity);
+            mInsetBottom = Bitmap.scaleFromDensity(mInsetBottom, sourceDensity, targetDensity);
+        }
+
+        @Override
+        public Drawable newDrawable(@Nullable Resources res) {
+            // If this drawable is being created for a different density,
+            // just create a new constant state and call it a day.
+            final InsetState state;
+            if (res != null) {
+                final int densityDpi = res.getDisplayMetrics().densityDpi;
+                final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+                if (density != mDensity) {
+                    state = new InsetState(this, res);
+                } else {
+                    state = this;
+                }
+            } else {
+                state = this;
+            }
+
+            return new InsetDrawable(state, res);
         }
     }
 
@@ -274,7 +310,7 @@
      * The one constructor to rule them all. This is called by all public
      * constructors to set the state and initialize local properties.
      */
-    private InsetDrawable(InsetState state, Resources res) {
+    private InsetDrawable(@NonNull InsetState state, @Nullable Resources res) {
         super(state, res);
 
         mState = state;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 1a0ba6f..4368fe9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -30,6 +30,7 @@
 import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.DisplayMetrics;
 import android.util.LayoutDirection;
 import android.view.Gravity;
 import android.view.View;
@@ -124,7 +125,7 @@
         final int length = layers.length;
         final ChildDrawable[] r = new ChildDrawable[length];
         for (int i = 0; i < length; i++) {
-            r[i] = new ChildDrawable();
+            r[i] = new ChildDrawable(mLayerState.mDensity);
             r[i].mDrawable = layers[i];
             layers[i].setCallback(this);
             mLayerState.mChildrenChangingConfigurations |= layers[i].getChangingConfigurations();
@@ -140,6 +141,10 @@
         this((LayerState) null, null);
     }
 
+    /**
+     * The one constructor to rule them all. This is called by all public
+     * constructors to set the state and initialize local properties.
+     */
     LayerDrawable(@Nullable LayerState state, @Nullable Resources res) {
         mLayerState = createConstantState(state, res);
         if (mLayerState.mNum > 0) {
@@ -153,24 +158,137 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         super.inflate(r, parser, attrs, theme);
 
+        final LayerState state = mLayerState;
+        if (state == null) {
+            return;
+        }
+
+        // The density may have changed since the last update. This will
+        // apply scaling to any existing constant state properties.
+        final int densityDpi = r.getDisplayMetrics().densityDpi;
+        final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+        state.setDensity(density);
+
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawable);
         updateStateFromTypedArray(a);
         a.recycle();
 
+        final ChildDrawable[] array = state.mChildren;
+        final int N = state.mNum;
+        for (int i = 0; i < N; i++) {
+            final ChildDrawable layer = array[i];
+            layer.setDensity(density);
+        }
+
         inflateLayers(r, parser, attrs, theme);
 
         ensurePadding();
         refreshPadding();
     }
 
+    @Override
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
+
+        final LayerState state = mLayerState;
+        if (state == null) {
+            return;
+        }
+
+        final int densityDpi = t.getResources().getDisplayMetrics().densityDpi;
+        final int density = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+        state.setDensity(density);
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.LayerDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+        }
+
+        final ChildDrawable[] array = state.mChildren;
+        final int N = state.mNum;
+        for (int i = 0; i < N; i++) {
+            final ChildDrawable layer = array[i];
+            layer.setDensity(density);
+
+            if (layer.mThemeAttrs != null) {
+                final TypedArray a = t.resolveAttributes(
+                        layer.mThemeAttrs, R.styleable.LayerDrawableItem);
+                updateLayerFromTypedArray(layer, a);
+                a.recycle();
+            }
+
+            final Drawable d = layer.mDrawable;
+            if (d != null && d.canApplyTheme()) {
+                d.applyTheme(t);
+
+                // Update cached mask of child changing configurations.
+                state.mChildrenChangingConfigurations |= d.getChangingConfigurations();
+            }
+        }
+    }
+
+    /**
+     * Inflates child layers using the specified parser.
+     */
+    private void inflateLayers(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
+            throws XmlPullParserException, IOException {
+        final LayerState state = mLayerState;
+
+        final int innerDepth = parser.getDepth() + 1;
+        int type;
+        int depth;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
+            if (type != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (depth > innerDepth || !parser.getName().equals("item")) {
+                continue;
+            }
+
+            final ChildDrawable layer = new ChildDrawable(state.mDensity);
+            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem);
+            updateLayerFromTypedArray(layer, a);
+            a.recycle();
+
+            // If the layer doesn't have a drawable or unresolved theme
+            // attribute for a drawable, attempt to parse one from the child
+            // element.
+            if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
+                    layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
+                while ((type = parser.next()) == XmlPullParser.TEXT) {
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException(parser.getPositionDescription()
+                            + ": <item> tag requires a 'drawable' attribute or "
+                            + "child tag defining a drawable");
+                }
+                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
+            }
+
+            if (layer.mDrawable != null) {
+                state.mChildrenChangingConfigurations |=
+                        layer.mDrawable.getChangingConfigurations();
+                layer.mDrawable.setCallback(this);
+            }
+
+            addLayer(layer);
+        }
+    }
+
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void updateStateFromTypedArray(TypedArray a) {
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
         final LayerState state = mLayerState;
 
         // Account for any configuration changes.
@@ -181,7 +299,7 @@
 
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
-            int attr = a.getIndex(i);
+            final int attr = a.getIndex(i);
             switch (attr) {
                 case R.styleable.LayerDrawable_opacity:
                     state.mOpacityOverride = a.getInt(attr, state.mOpacityOverride);
@@ -214,57 +332,7 @@
         }
     }
 
-    /**
-     * Inflates child layers using the specified parser.
-     */
-    private void inflateLayers(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
-            throws XmlPullParserException, IOException {
-        final LayerState state = mLayerState;
-
-        final int innerDepth = parser.getDepth() + 1;
-        int type;
-        int depth;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && ((depth = parser.getDepth()) >= innerDepth || type != XmlPullParser.END_TAG)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if (depth > innerDepth || !parser.getName().equals("item")) {
-                continue;
-            }
-
-            final ChildDrawable layer = new ChildDrawable();
-            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.LayerDrawableItem);
-            updateLayerFromTypedArray(layer, a);
-            a.recycle();
-
-            // If the layer doesn't have a drawable or unresolved theme
-            // attribute for a drawable, attempt to parse one from the child
-            // element.
-            if (layer.mDrawable == null && (layer.mThemeAttrs == null ||
-                    layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) {
-                while ((type = parser.next()) == XmlPullParser.TEXT) {
-                }
-                if (type != XmlPullParser.START_TAG) {
-                    throw new XmlPullParserException(parser.getPositionDescription()
-                            + ": <item> tag requires a 'drawable' attribute or "
-                            + "child tag defining a drawable");
-                }
-                layer.mDrawable = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            }
-
-            if (layer.mDrawable != null) {
-                state.mChildrenChangingConfigurations |=
-                        layer.mDrawable.getChangingConfigurations();
-                layer.mDrawable.setCallback(this);
-            }
-
-            addLayer(layer);
-        }
-    }
-
-    private void updateLayerFromTypedArray(ChildDrawable layer, TypedArray a) {
+    private void updateLayerFromTypedArray(@NonNull ChildDrawable layer, @NonNull TypedArray a) {
         final LayerState state = mLayerState;
 
         // Account for any configuration changes.
@@ -273,25 +341,42 @@
         // Extract the theme attributes, if any.
         layer.mThemeAttrs = a.extractThemeAttrs();
 
-        layer.mInsetL = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_left, layer.mInsetL);
-        layer.mInsetT = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_top, layer.mInsetT);
-        layer.mInsetR = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_right, layer.mInsetR);
-        layer.mInsetB = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_bottom, layer.mInsetB);
-        layer.mInsetS = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_start, layer.mInsetS);
-        layer.mInsetE = a.getDimensionPixelOffset(
-                R.styleable.LayerDrawableItem_end, layer.mInsetE);
-        layer.mWidth = a.getDimensionPixelSize(
-                R.styleable.LayerDrawableItem_width, layer.mWidth);
-        layer.mHeight = a.getDimensionPixelSize(
-                R.styleable.LayerDrawableItem_height, layer.mHeight);
-        layer.mGravity = a.getInteger(
-                R.styleable.LayerDrawableItem_gravity, layer.mGravity);
-        layer.mId = a.getResourceId(R.styleable.LayerDrawableItem_id, layer.mId);
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            final int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.LayerDrawableItem_left:
+                    layer.mInsetL = a.getDimensionPixelOffset(attr, layer.mInsetL);
+                    break;
+                case R.styleable.LayerDrawableItem_top:
+                    layer.mInsetT = a.getDimensionPixelOffset(attr, layer.mInsetT);
+                    break;
+                case R.styleable.LayerDrawableItem_right:
+                    layer.mInsetR = a.getDimensionPixelOffset(attr, layer.mInsetR);
+                    break;
+                case R.styleable.LayerDrawableItem_bottom:
+                    layer.mInsetB = a.getDimensionPixelOffset(attr, layer.mInsetB);
+                    break;
+                case R.styleable.LayerDrawableItem_start:
+                    layer.mInsetS = a.getDimensionPixelOffset(attr, layer.mInsetS);
+                    break;
+                case R.styleable.LayerDrawableItem_end:
+                    layer.mInsetE = a.getDimensionPixelOffset(attr, layer.mInsetE);
+                    break;
+                case R.styleable.LayerDrawableItem_width:
+                    layer.mWidth = a.getDimensionPixelSize(attr, layer.mWidth);
+                    break;
+                case R.styleable.LayerDrawableItem_height:
+                    layer.mHeight = a.getDimensionPixelSize(attr, layer.mHeight);
+                    break;
+                case R.styleable.LayerDrawableItem_gravity:
+                    layer.mGravity = a.getInteger(attr, layer.mGravity);
+                    break;
+                case R.styleable.LayerDrawableItem_id:
+                    layer.mId = a.getResourceId(attr, layer.mId);
+                    break;
+            }
+        }
 
         final Drawable dr = a.getDrawable(R.styleable.LayerDrawableItem_drawable);
         if (dr != null) {
@@ -300,44 +385,6 @@
     }
 
     @Override
-    public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
-        final LayerState state = mLayerState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.LayerDrawable);
-            updateStateFromTypedArray(a);
-            a.recycle();
-        }
-
-        final ChildDrawable[] array = state.mChildren;
-        final int N = state.mNum;
-        for (int i = 0; i < N; i++) {
-            final ChildDrawable layer = array[i];
-            if (layer.mThemeAttrs != null) {
-                final TypedArray a = t.resolveAttributes(layer.mThemeAttrs,
-                        R.styleable.LayerDrawableItem);
-                updateLayerFromTypedArray(layer, a);
-                a.recycle();
-            }
-
-            final Drawable d = layer.mDrawable;
-            if (d != null && d.canApplyTheme()) {
-                d.applyTheme(t);
-
-                // Update cached mask of child changing configurations.
-                state.mChildrenChangingConfigurations |= d.getChangingConfigurations();
-            }
-        }
-
-        ensurePadding();
-    }
-
-    @Override
     public boolean canApplyTheme() {
         return (mLayerState != null && mLayerState.canApplyTheme()) || super.canApplyTheme();
     }
@@ -368,7 +415,7 @@
      * @param layer The layer to add.
      * @return The index of the layer.
      */
-    int addLayer(ChildDrawable layer) {
+    int addLayer(@NonNull ChildDrawable layer) {
         final LayerState st = mLayerState;
         final int N = st.mChildren != null ? st.mChildren.length : 0;
         final int i = st.mNum;
@@ -418,7 +465,7 @@
     }
 
     private ChildDrawable createLayer(Drawable dr) {
-        final ChildDrawable layer = new ChildDrawable();
+        final ChildDrawable layer = new ChildDrawable(mLayerState.mDensity);
         layer.mDrawable = dr;
         return layer;
     }
@@ -1708,6 +1755,7 @@
     static class ChildDrawable {
         public Drawable mDrawable;
         public int[] mThemeAttrs;
+        public int mDensity = DisplayMetrics.DENSITY_DEFAULT;
         public int mInsetL, mInsetT, mInsetR, mInsetB;
         public int mInsetS = UNDEFINED_INSET;
         public int mInsetE = UNDEFINED_INSET;
@@ -1716,11 +1764,12 @@
         public int mGravity = Gravity.NO_GRAVITY;
         public int mId = View.NO_ID;
 
-        ChildDrawable() {
-            // Default empty constructor.
+        ChildDrawable(int density) {
+            mDensity = density;
         }
 
-        ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) {
+        ChildDrawable(@NonNull ChildDrawable orig, @NonNull LayerDrawable owner,
+                @Nullable Resources res) {
             final Drawable dr = orig.mDrawable;
             final Drawable clone;
             if (dr != null) {
@@ -1750,19 +1799,58 @@
             mHeight = orig.mHeight;
             mGravity = orig.mGravity;
             mId = orig.mId;
+
+            final int densityDpi = res == null ? orig.mDensity : res.getDisplayMetrics().densityDpi;
+            mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+
+            if (orig.mDensity != mDensity) {
+                applyDensityScaling(orig.mDensity, mDensity);
+            }
         }
 
         public boolean canApplyTheme() {
             return mThemeAttrs != null
                     || (mDrawable != null && mDrawable.canApplyTheme());
         }
+
+        public final void setDensity(int targetDensity) {
+            if (mDensity != targetDensity) {
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
+
+                applyDensityScaling(sourceDensity, targetDensity);
+            }
+        }
+
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            mInsetL = Bitmap.scaleFromDensity(mInsetL, sourceDensity, targetDensity);
+            mInsetT = Bitmap.scaleFromDensity(mInsetT, sourceDensity, targetDensity);
+            mInsetR = Bitmap.scaleFromDensity(mInsetR, sourceDensity, targetDensity);
+            mInsetB = Bitmap.scaleFromDensity(mInsetB, sourceDensity, targetDensity);
+            if (mInsetS != UNDEFINED_INSET) {
+                mInsetS = Bitmap.scaleFromDensity(mInsetS, sourceDensity, targetDensity);
+            }
+            if (mInsetE != UNDEFINED_INSET) {
+                mInsetE = Bitmap.scaleFromDensity(mInsetE, sourceDensity, targetDensity);
+            }
+            if (mWidth > 0) {
+                mWidth = Bitmap.scaleFromDensity(mWidth, sourceDensity, targetDensity);
+            }
+            if (mHeight > 0) {
+                mHeight = Bitmap.scaleFromDensity(mHeight, sourceDensity, targetDensity);
+            }
+        }
     }
 
     static class LayerState extends ConstantState {
+        private int[] mThemeAttrs;
+
         int mNum;
         ChildDrawable[] mChildren;
-        int[] mThemeAttrs;
 
+        int mDensity;
+
+        // These values all correspond to mDensity.
         int mPaddingTop = -1;
         int mPaddingBottom = -1;
         int mPaddingLeft = -1;
@@ -1784,7 +1872,19 @@
 
         private int mPaddingMode = PADDING_MODE_NEST;
 
-        LayerState(LayerState orig, LayerDrawable owner, Resources res) {
+        LayerState(@Nullable LayerState orig, @NonNull LayerDrawable owner,
+                @Nullable Resources res) {
+            final int densityDpi;
+            if (res != null) {
+                densityDpi = res.getDisplayMetrics().densityDpi;
+            } else if (orig != null) {
+                densityDpi = orig.mDensity;
+            } else {
+                densityDpi = 0;
+            }
+
+            mDensity = densityDpi == 0 ? DisplayMetrics.DENSITY_DEFAULT : densityDpi;
+
             if (orig != null) {
                 final ChildDrawable[] origChildDrawable = orig.mChildren;
                 final int N = orig.mNum;
@@ -1814,12 +1914,56 @@
                 mPaddingStart = orig.mPaddingStart;
                 mPaddingEnd = orig.mPaddingEnd;
                 mOpacityOverride = orig.mOpacityOverride;
+
+                if (orig.mDensity != mDensity) {
+                    applyDensityScaling(orig.mDensity, mDensity);
+                }
             } else {
                 mNum = 0;
                 mChildren = null;
             }
         }
 
+        public final void setDensity(int targetDensity) {
+            if (mDensity != targetDensity) {
+                final int sourceDensity = mDensity;
+                mDensity = targetDensity;
+
+                onDensityChanged(sourceDensity, targetDensity);
+            }
+        }
+
+        protected void onDensityChanged(int sourceDensity, int targetDensity) {
+            applyDensityScaling(sourceDensity, targetDensity);
+        }
+
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            if (mPaddingLeft > 0) {
+                mPaddingLeft = Bitmap.scaleFromDensity(
+                        mPaddingLeft, sourceDensity, targetDensity);
+            }
+            if (mPaddingTop > 0) {
+                mPaddingTop = Bitmap.scaleFromDensity(
+                        mPaddingTop, sourceDensity, targetDensity);
+            }
+            if (mPaddingRight > 0) {
+                mPaddingRight = Bitmap.scaleFromDensity(
+                        mPaddingRight, sourceDensity, targetDensity);
+            }
+            if (mPaddingBottom > 0) {
+                mPaddingBottom = Bitmap.scaleFromDensity(
+                        mPaddingBottom, sourceDensity, targetDensity);
+            }
+            if (mPaddingStart > 0) {
+                mPaddingStart = Bitmap.scaleFromDensity(
+                        mPaddingStart, sourceDensity, targetDensity);
+            }
+            if (mPaddingEnd > 0) {
+                mPaddingEnd = Bitmap.scaleFromDensity(
+                        mPaddingEnd, sourceDensity, targetDensity);
+            }
+        }
+
         @Override
         public boolean canApplyTheme() {
             if (mThemeAttrs != null || super.canApplyTheme()) {
@@ -1844,7 +1988,7 @@
         }
 
         @Override
-        public Drawable newDrawable(Resources res) {
+        public Drawable newDrawable(@Nullable Resources res) {
             return new LayerDrawable(this, res);
         }
 
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 2690223..a196fad 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -409,18 +409,20 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RippleDrawable);
-        updateStateFromTypedArray(a);
-        a.recycle();
 
         // Force padding default to STACK before inflating.
         setPaddingMode(PADDING_MODE_STACK);
 
+        // Inflation will advance the XmlPullParser and AttributeSet.
         super.inflate(r, parser, attrs, theme);
 
-        setTargetDensity(r.getDisplayMetrics());
+        updateStateFromTypedArray(a);
+        verifyRequiredAttributes(a);
+        a.recycle();
 
         updateLocalState();
     }
@@ -461,7 +463,7 @@
     /**
      * Initializes the constant state from the values in the typed array.
      */
-    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+    private void updateStateFromTypedArray(@NonNull TypedArray a) throws XmlPullParserException {
         final RippleState state = mState;
 
         // Account for any configuration changes.
@@ -477,11 +479,9 @@
 
         mState.mMaxRadius = a.getDimensionPixelSize(
                 R.styleable.RippleDrawable_radius, mState.mMaxRadius);
-
-        verifyRequiredAttributes(a);
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
         if (mState.mColor == null && (mState.mTouchThemeAttrs == null
                 || mState.mTouchThemeAttrs[R.styleable.RippleDrawable_color] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription() +
@@ -489,20 +489,8 @@
         }
     }
 
-    /**
-     * Set the density at which this drawable will be rendered.
-     *
-     * @param metrics The display metrics for this drawable.
-     */
-    private void setTargetDensity(DisplayMetrics metrics) {
-        if (mDensity != metrics.density) {
-            mDensity = metrics.density;
-            invalidateSelf(false);
-        }
-    }
-
     @Override
-    public void applyTheme(Theme t) {
+    public void applyTheme(@NonNull Theme t) {
         super.applyTheme(t);
 
         final RippleState state = mState;
@@ -515,6 +503,7 @@
                     R.styleable.RippleDrawable);
             try {
                 updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
             } catch (XmlPullParserException e) {
                 throw new RuntimeException(e);
             } finally {
@@ -555,7 +544,8 @@
             mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware);
         }
 
-        mBackground.setup(mState.mMaxRadius, mDensity);
+        final float densityScale = mState.mDensity * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        mBackground.setup(mState.mMaxRadius, densityScale);
         mBackground.enter(focused);
     }
 
@@ -1002,6 +992,23 @@
                 mTouchThemeAttrs = origs.mTouchThemeAttrs;
                 mColor = origs.mColor;
                 mMaxRadius = origs.mMaxRadius;
+
+                if (origs.mDensity != mDensity) {
+                    applyDensityScaling(orig.mDensity, mDensity);
+                }
+            }
+        }
+
+        @Override
+        protected void onDensityChanged(int sourceDensity, int targetDensity) {
+            super.onDensityChanged(sourceDensity, targetDensity);
+
+            applyDensityScaling(sourceDensity, targetDensity);
+        }
+
+        private void applyDensityScaling(int sourceDensity, int targetDensity) {
+            if (mMaxRadius != RADIUS_AUTO) {
+                mMaxRadius = Bitmap.scaleFromDensity(mMaxRadius, sourceDensity, targetDensity);
             }
         }
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 036a078..1531ba2 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -21,6 +21,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.graphics.Canvas;
 import android.graphics.Rect;
 import android.content.res.Resources;
@@ -58,22 +60,46 @@
      * Creates a new rotating drawable with no wrapped drawable.
      */
     public RotateDrawable() {
-        this(new RotateState(null), null);
+        this(new RotateState(null, null), null);
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
-        super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_visible);
+
+        // Inflation will advance the XmlPullParser and AttributeSet.
+        super.inflate(r, parser, attrs, theme);
 
         updateStateFromTypedArray(a);
-        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+    @Override
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
+
+        final RotateState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+    }
+
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
         if (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.RotateDrawable_drawable] == 0)) {
@@ -83,11 +109,14 @@
         }
     }
 
-    @Override
-    void updateStateFromTypedArray(TypedArray a) {
-        super.updateStateFromTypedArray(a);
-
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
         final RotateState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
 
         // Extract the theme attributes, if any.
         state.mThemeAttrs = a.extractThemeAttrs();
@@ -109,35 +138,6 @@
         state.mToDegrees = a.getFloat(
                 R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
         state.mCurrentDegrees = state.mFromDegrees;
-
-        final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
-        if (dr != null) {
-            setDrawable(dr);
-        }
-    }
-
-    @Override
-    public void applyTheme(Theme t) {
-        final RotateState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        // The drawable may have changed as a result of applying the theme, so
-        // apply the theme to the wrapped drawable last.
-        super.applyTheme(t);
     }
 
     @Override
@@ -316,11 +316,13 @@
 
     @Override
     DrawableWrapperState mutateConstantState() {
-        mState = new RotateState(mState);
+        mState = new RotateState(mState, null);
         return mState;
     }
 
     static final class RotateState extends DrawableWrapper.DrawableWrapperState {
+        private int[] mThemeAttrs;
+
         boolean mPivotXRel = true;
         float mPivotX = 0.5f;
         boolean mPivotYRel = true;
@@ -329,8 +331,8 @@
         float mToDegrees = 360.0f;
         float mCurrentDegrees = 0.0f;
 
-        RotateState(RotateState orig) {
-            super(orig);
+        RotateState(RotateState orig, Resources res) {
+            super(orig, res);
 
             if (orig != null) {
                 mPivotXRel = orig.mPivotXRel;
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index f9206b7..f87c19a 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -21,6 +21,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
@@ -67,7 +69,7 @@
     private ScaleState mState;
 
     ScaleDrawable() {
-        this(new ScaleState(null), null);
+        this(new ScaleState(null, null), null);
     }
 
     /**
@@ -83,7 +85,7 @@
      *                    is at the maximum value, or -1 to not scale height
      */
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
-        this(new ScaleState(null), null);
+        this(new ScaleState(null, null), null);
 
         mState.mGravity = gravity;
         mState.mScaleWidth = scaleWidth;
@@ -93,20 +95,46 @@
     }
 
     @Override
-    public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
+    public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
+            @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
+
+        // Inflation will advance the XmlPullParser and AttributeSet.
         super.inflate(r, parser, attrs, theme);
 
-        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
         updateStateFromTypedArray(a);
-        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
 
         updateLocalState();
     }
 
-    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+    @Override
+    public void applyTheme(@NonNull Theme t) {
+        super.applyTheme(t);
+
+        final ScaleState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        updateLocalState();
+    }
+
+    private void verifyRequiredAttributes(@NonNull TypedArray a) throws XmlPullParserException {
         // If we're not waiting on a theme, verify required attributes.
         if (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
@@ -116,11 +144,18 @@
         }
     }
 
-    @Override
-    void updateStateFromTypedArray(TypedArray a) {
-        super.updateStateFromTypedArray(a);
-
+    private void updateStateFromTypedArray(@NonNull TypedArray a) {
         final ScaleState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
         state.mScaleWidth = getPercent(a,
                 R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
         state.mScaleHeight = getPercent(a,
@@ -131,11 +166,6 @@
                 R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
         state.mInitialLevel = a.getInt(
                 R.styleable.ScaleDrawable_level, state.mInitialLevel);
-
-        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
-        if (dr != null) {
-            setDrawable(dr);
-        }
     }
 
     private static float getPercent(TypedArray a, int index, float defaultValue) {
@@ -157,33 +187,6 @@
     }
 
     @Override
-    public void applyTheme(Theme t) {
-        final ScaleState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    state.mThemeAttrs, R.styleable.ScaleDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        // The drawable may have changed as a result of applying the theme, so
-        // apply the theme to the wrapped drawable last.
-        super.applyTheme(t);
-
-        updateLocalState();
-    }
-
-    @Override
     public void draw(Canvas canvas) {
         final Drawable d = getDrawable();
         if (d != null && d.getLevel() != 0) {
@@ -243,7 +246,7 @@
 
     @Override
     DrawableWrapperState mutateConstantState() {
-        mState = new ScaleState(mState);
+        mState = new ScaleState(mState, null);
         return mState;
     }
 
@@ -251,14 +254,16 @@
         /** Constant used to disable scaling for a particular dimension. */
         private static final float DO_NOT_SCALE = -1.0f;
 
+        private int[] mThemeAttrs;
+
         float mScaleWidth = DO_NOT_SCALE;
         float mScaleHeight = DO_NOT_SCALE;
         int mGravity = Gravity.LEFT;
         boolean mUseIntrinsicSizeAsMin = false;
         int mInitialLevel = 0;
 
-        ScaleState(ScaleState orig) {
-            super(orig);
+        ScaleState(ScaleState orig, Resources res) {
+            super(orig, res);
 
             if (orig != null) {
                 mScaleWidth = orig.mScaleWidth;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 842f575..d94c91d 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -27,6 +27,7 @@
     utils/LinearAllocator.cpp \
     utils/NinePatchImpl.cpp \
     utils/StringUtils.cpp \
+    utils/TestWindowContext.cpp \
     AmbientShadow.cpp \
     AnimationContext.cpp \
     Animator.cpp \
@@ -84,8 +85,7 @@
 hwui_cflags := \
     -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES \
     -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" \
-    -Wall -Wno-unused-parameter -Wunreachable-code \
-    -ffast-math -O3 -Werror
+    -Wall -Wno-unused-parameter -Wunreachable-code -Werror
 
 ifeq (true, $(HWUI_NEW_OPS))
     hwui_src_files += \
@@ -113,6 +113,7 @@
 endef
 
 hwui_c_includes += \
+    external/skia/include/private \
     external/skia/src/core
 
 hwui_shared_libraries := \
@@ -202,6 +203,7 @@
     unit_tests/CanvasStateTests.cpp \
     unit_tests/ClipAreaTests.cpp \
     unit_tests/DamageAccumulatorTests.cpp \
+    unit_tests/FatVectorTests.cpp \
     unit_tests/LinearAllocatorTests.cpp \
     unit_tests/StringUtilsTests.cpp
 
@@ -261,7 +263,8 @@
 
 LOCAL_SRC_FILES += \
     microbench/DisplayListCanvasBench.cpp \
-    microbench/LinearAllocatorBench.cpp
+    microbench/LinearAllocatorBench.cpp \
+    microbench/ShadowBench.cpp
 
 ifeq (true, $(HWUI_NEW_OPS))
     LOCAL_SRC_FILES += \
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 94806ca..0868853 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -25,112 +25,210 @@
 namespace android {
 namespace uirenderer {
 
-Texture* BakedOpRenderer::Info::getTexture(const SkBitmap* bitmap) {
-    Texture* texture = renderState.assetAtlas().getEntryTexture(bitmap);
-    if (!texture) {
-        return caches.textureCache.get(bitmap);
-    }
-    return texture;
+////////////////////////////////////////////////////////////////////////////////
+// OffscreenBuffer
+////////////////////////////////////////////////////////////////////////////////
+
+OffscreenBuffer::OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight,
+        uint32_t viewportWidth, uint32_t viewportHeight)
+        : texture(caches)
+        , texCoords(0, viewportHeight / float(textureHeight), viewportWidth / float(textureWidth), 0) {
+    texture.width = textureWidth;
+    texture.height = textureHeight;
+
+    caches.textureState().activateTexture(0);
+    glGenTextures(1, &texture.id);
+    caches.textureState().bindTexture(GL_TEXTURE_2D, texture.id);
+
+    texture.setWrap(GL_CLAMP_TO_EDGE, false, false, GL_TEXTURE_2D);
+    // not setting filter on texture, since it's set when drawing, based on transform
+
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture.width, texture.height, 0,
+            GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
 }
 
-void BakedOpRenderer::Info::renderGlop(const BakedOpState& state, const Glop& glop) {
-    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
-    renderState.scissor().setEnabled(useScissor);
-    if (useScissor) {
-        const Rect& clip = state.computedState.clipRect;
-        renderState.scissor().set(clip.left, viewportHeight - clip.bottom,
-            clip.getWidth(), clip.getHeight());
-    }
-    renderState.render(glop, orthoMatrix);
-    didDraw = true;
+////////////////////////////////////////////////////////////////////////////////
+// BakedOpRenderer
+////////////////////////////////////////////////////////////////////////////////
+
+OffscreenBuffer* BakedOpRenderer::startLayer(uint32_t width, uint32_t height) {
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
+
+    // TODO: really should be caching these!
+    OffscreenBuffer* buffer = new OffscreenBuffer(mCaches, width, height, width, height);
+    mRenderTarget.offscreenBuffer = buffer;
+
+    // create and bind framebuffer
+    mRenderTarget.frameBufferId = mRenderState.genFramebuffer();
+    mRenderState.bindFramebuffer(mRenderTarget.frameBufferId);
+
+    // attach the texture to the FBO
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+            buffer->texture.id, 0);
+    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "startLayer FAILED");
+    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
+            "framebuffer incomplete!");
+
+    // Clear the FBO
+    mRenderState.scissor().setEnabled(false);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    // Change the viewport & ortho projection
+    setViewport(width, height);
+    return buffer;
 }
 
-void BakedOpRenderer::startFrame(Info& info) {
-    info.renderState.setViewport(info.viewportWidth, info.viewportHeight);
-    info.renderState.blend().syncEnabled();
-    Caches::getInstance().clearGarbage();
+void BakedOpRenderer::endLayer() {
+    mRenderTarget.offscreenBuffer = nullptr;
 
-    if (!info.opaque) {
+    // Detach the texture from the FBO
+    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
+    LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
+    mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
+    mRenderTarget.frameBufferId = -1;
+}
+
+void BakedOpRenderer::startFrame(uint32_t width, uint32_t height) {
+    mRenderState.bindFramebuffer(0);
+    setViewport(width, height);
+    mCaches.clearGarbage();
+
+    if (!mOpaque) {
         // TODO: partial invalidate!
-        info.renderState.scissor().setEnabled(false);
+        mRenderState.scissor().setEnabled(false);
         glClear(GL_COLOR_BUFFER_BIT);
-        info.didDraw = true;
+        mHasDrawn = true;
     }
 }
-void BakedOpRenderer::endFrame(Info& info) {
-    info.caches.pathCache.trim();
-    info.caches.tessellationCache.trim();
+
+void BakedOpRenderer::endFrame() {
+    mCaches.pathCache.trim();
+    mCaches.tessellationCache.trim();
 
 #if DEBUG_OPENGL
     GLUtils::dumpGLErrors();
 #endif
 
 #if DEBUG_MEMORY_USAGE
-    info.caches.dumpMemoryUsage();
+    mCaches.dumpMemoryUsage();
 #else
     if (Properties::debugLevel & kDebugMemory) {
-        info.caches.dumpMemoryUsage();
+        mCaches.dumpMemoryUsage();
     }
 #endif
 }
 
-void BakedOpRenderer::onRenderNodeOp(Info&, const RenderNodeOp&, const BakedOpState&) {
+void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
+    mRenderTarget.viewportWidth = width;
+    mRenderTarget.viewportHeight = height;
+    mRenderTarget.orthoMatrix.loadOrtho(width, height);
+
+    mRenderState.setViewport(width, height);
+    mRenderState.blend().syncEnabled();
+}
+
+Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
+    Texture* texture = mRenderState.assetAtlas().getEntryTexture(bitmap);
+    if (!texture) {
+        return mCaches.textureCache.get(bitmap);
+    }
+    return texture;
+}
+
+void BakedOpRenderer::renderGlop(const BakedOpState& state, const Glop& glop) {
+    bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
+    mRenderState.scissor().setEnabled(useScissor);
+    if (useScissor) {
+        const Rect& clip = state.computedState.clipRect;
+        mRenderState.scissor().set(clip.left, mRenderTarget.viewportHeight - clip.bottom,
+            clip.getWidth(), clip.getHeight());
+    }
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    mHasDrawn = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// static BakedOpDispatcher methods
+////////////////////////////////////////////////////////////////////////////////
+
+void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) {
-    info.caches.textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
-    Texture* texture = info.getTexture(op.bitmap);
+void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
+    renderer.caches().textureState().activateTexture(0); // TODO: should this be automatic, and/or elsewhere?
+    Texture* texture = renderer.getTexture(op.bitmap);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
     const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
             ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshTexturedUnitQuad(texture->uvMapper)
             .setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onRectOp(Info& info, const RectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshUnitQuad()
             .setFillPaint(*op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewMapUnitToRect(op.unmappedBounds)
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onSimpleRectsOp(Info& info, const SimpleRectsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
     Glop glop;
-    GlopBuilder(info.renderState, info.caches, &glop)
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
             .setRoundRectClipState(state.roundRectClipState)
             .setMeshIndexedQuads(&op.vertices[0], op.vertexCount / 4)
             .setFillPaint(*op.paint, state.alpha)
             .setTransform(state.computedState.transform, TransformFlags::None)
             .setModelViewOffsetRect(0, 0, op.unmappedBounds)
             .build();
-    info.renderGlop(state, glop);
+    renderer.renderGlop(state, glop);
 }
 
-void BakedOpRenderer::onBeginLayerOp(Info& info, const BeginLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer& renderer, const BeginLayerOp& op, const BakedOpState& state) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onEndLayerOp(Info& info, const EndLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer& renderer, const EndLayerOp& op, const BakedOpState& state) {
     LOG_ALWAYS_FATAL("unsupported operation");
 }
 
-void BakedOpRenderer::onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) {
-    LOG_ALWAYS_FATAL("unsupported operation");
+void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
+    OffscreenBuffer* buffer = *op.layerHandle;
+
+    // TODO: extend this to handle HW layers & paint properties which
+    // reside in node.properties().layerProperties()
+    float layerAlpha = (op.paint->getAlpha() / 255.0f) * state.alpha;
+    const bool tryToSnap = state.computedState.transform.isPureTranslate();
+    Glop glop;
+    GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
+            .setRoundRectClipState(state.roundRectClipState)
+            .setMeshTexturedUvQuad(nullptr, buffer->texCoords)
+            .setFillLayer(buffer->texture, op.paint->getColorFilter(), layerAlpha, PaintUtils::getXfermodeDirect(op.paint), Blend::ModeOrderSwap::NoSwap)
+            .setTransform(state.computedState.transform, TransformFlags::None)
+            .setModelViewMapUnitToRectOptionalSnap(tryToSnap, op.unmappedBounds)
+            .build();
+    renderer.renderGlop(state, glop);
+
+    // destroy and delete, since each clipped saveLayer is only drawn once.
+    buffer->texture.deleteTexture();
+
+    // TODO: return texture/offscreenbuffer to cache!
+    delete buffer;
 }
 
 } // namespace uirenderer
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index f45dbe4..16afad4 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -25,48 +25,85 @@
 
 class Caches;
 struct Glop;
+class Layer;
 class RenderState;
 
+/**
+ * Lightweight alternative to Layer. Owns the persistent state of an offscreen render target, and
+ * encompasses enough information to draw it back on screen (minus paint properties, which are held
+ * by LayerOp).
+ */
+class OffscreenBuffer {
+public:
+    OffscreenBuffer(Caches& caches, uint32_t textureWidth, uint32_t textureHeight,
+            uint32_t viewportWidth, uint32_t viewportHeight);
+
+    Texture texture;
+    Rect texCoords;
+    Region region;
+};
+
+/**
+ * Main rendering manager for a collection of work - one frame + any contained FBOs.
+ *
+ * Manages frame and FBO lifecycle, binding the GL framebuffer as appropriate. This is the only
+ * place where FBOs are bound, created, and destroyed.
+ *
+ * All rendering operations will be sent by the Dispatcher, a collection of static methods,
+ * which has intentionally limited access to the renderer functionality.
+ */
 class BakedOpRenderer {
 public:
-    class Info {
-    public:
-        Info(Caches& caches, RenderState& renderState, int viewportWidth, int viewportHeight, bool opaque)
-                : renderState(renderState)
-                , caches(caches)
-                , opaque(opaque)
-                , viewportWidth(viewportWidth)
-                , viewportHeight(viewportHeight) {
-            orthoMatrix.loadOrtho(viewportWidth, viewportHeight);
-        }
+    BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque)
+            : mRenderState(renderState)
+            , mCaches(caches)
+            , mOpaque(opaque) {
+    }
 
-        Texture* getTexture(const SkBitmap* bitmap);
+    RenderState& renderState() { return mRenderState; }
+    Caches& caches() { return mCaches; }
 
-        void renderGlop(const BakedOpState& state, const Glop& glop);
-        RenderState& renderState;
-        Caches& caches;
+    void startFrame(uint32_t width, uint32_t height);
+    void endFrame();
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height);
+    void endLayer();
 
-        bool didDraw = false;
-        bool opaque;
+    Texture* getTexture(const SkBitmap* bitmap);
 
+    void renderGlop(const BakedOpState& state, const Glop& glop);
+    bool didDraw() { return mHasDrawn; }
+private:
+    void setViewport(uint32_t width, uint32_t height);
 
-        // where should these live? layer state object?
-        int viewportWidth;
-        int viewportHeight;
+    RenderState& mRenderState;
+    Caches& mCaches;
+    bool mOpaque;
+    bool mHasDrawn = false;
+
+    // render target state - setup by start/end layer/frame
+    // only valid to use in between start/end pairs.
+    struct {
+        GLuint frameBufferId = 0;
+        OffscreenBuffer* offscreenBuffer = nullptr;
+        uint32_t viewportWidth = 0;
+        uint32_t viewportHeight = 0;
         Matrix4 orthoMatrix;
-    };
+    } mRenderTarget;
+};
 
-    static void startFrame(Info& info);
-    static void endFrame(Info& info);
-
-    /**
-     * Declare all "onBitmapOp(...)" style function for every op type.
-     *
-     * These functions will perform the actual rendering of the individual operations in OpenGL,
-     * given the transform/clip and other state built into the BakedOpState object passed in.
-     */
-    #define BAKED_OP_RENDERER_METHOD(Type) static void on##Type(Info& info, const Type& op, const BakedOpState& state);
-    MAP_OPS(BAKED_OP_RENDERER_METHOD);
+/**
+ * Provides all "onBitmapOp(...)" style static methods for every op type, which convert the
+ * RecordedOps and their state to Glops, and renders them with the provided BakedOpRenderer.
+ *
+ * This dispatcher is separate from the renderer so that the dispatcher / renderer interaction is
+ * minimal through public BakedOpRenderer APIs.
+ */
+class BakedOpDispatcher {
+public:
+    // Declares all "onBitmapOp(...)" style methods for every op type
+#define DISPATCH_METHOD(Type) \
+        static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
+    MAP_OPS(DISPATCH_METHOD);
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index bad3972..f5e5735 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -584,7 +584,7 @@
     // it to the bitmap pile
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
-    if (shader->asABitmap(&bitmap, nullptr, xy) == SkShader::kDefault_BitmapType) {
+    if (shader->isABitmap(&bitmap, nullptr, xy)) {
         refBitmap(bitmap);
         return;
     }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index f99d92b..489ebc1 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -155,8 +155,7 @@
 
     if (fbo) {
         if (flush) LayerRenderer::flushLayer(renderState, this);
-        // If put fails the cache will delete the FBO
-        caches.fboCache.put(fbo);
+        renderState.deleteFramebuffer(fbo);
         fbo = 0;
     }
 }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 227271d..e9e5d81 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -189,7 +189,7 @@
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
     Caches& caches = Caches::getInstance();
-    GLuint fbo = caches.fboCache.get();
+    GLuint fbo = renderState.genFramebuffer();
     if (!fbo) {
         ALOGW("Could not obtain an FBO");
         return nullptr;
@@ -204,7 +204,7 @@
 
     // We first obtain a layer before comparing against the max texture size
     // because layers are not allocated at the exact desired size. They are
-    // always created slighly larger to improve recycling
+    // always created slightly larger to improve recycling
     const uint32_t maxTextureSize = caches.maxTextureSize;
     if (layer->getWidth() > maxTextureSize || layer->getHeight() > maxTextureSize) {
         ALOGW("Layer exceeds max. dimensions supported by the GPU (%dx%d, max=%dx%d)",
@@ -357,7 +357,7 @@
             && bitmap->width() <= caches.maxTextureSize
             && bitmap->height() <= caches.maxTextureSize) {
 
-        GLuint fbo = caches.fboCache.get();
+        GLuint fbo = renderState.getFramebuffer();
         if (!fbo) {
             ALOGW("Could not obtain an FBO");
             return false;
@@ -465,7 +465,7 @@
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
         caches.textureState().deleteTexture(texture);
-        caches.fboCache.put(fbo);
+        renderState.deleteFramebuffer(fbo);
         renderState.setViewport(previousViewportWidth, previousViewportHeight);
 
         return status;
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index c1417c4..ddeb336 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -203,7 +203,7 @@
 };
 
 // iterate back toward target to see if anything drawn since should overlap the new op
-// if no target, merging ops still interate to find similar batch to insert after
+// if no target, merging ops still iterate to find similar batch to insert after
 void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& clippedBounds,
         BatchBase** targetBatch, size_t* insertBatchIndex) const {
     for (int i = mBatches.size() - 1; i >= 0; i--) {
@@ -277,7 +277,8 @@
     }
 }
 
-void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const {
+void OpReorderer::LayerReorderer::replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const {
+    ATRACE_NAME("flush drawing commands");
     for (const BatchBase* batch : mBatches) {
         // TODO: different behavior based on batch->isMerging()
         for (const BakedOpState* op : batch->getOps()) {
@@ -292,18 +293,14 @@
     }
 }
 
-OpReorderer::OpReorderer()
+OpReorderer::OpReorderer(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
+        const std::vector< sp<RenderNode> >& nodes)
         : mCanvasState(*this) {
-    mLayerReorderers.emplace_back();
+    ATRACE_NAME("prepare drawing commands");
+
+    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
     mLayerStack.push_back(0);
-}
 
-void OpReorderer::onViewportInitialized() {}
-
-void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
-
-void OpReorderer::defer(const SkRect& clip, int viewportWidth, int viewportHeight,
-        const std::vector< sp<RenderNode> >& nodes) {
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
             Vector3());
@@ -321,13 +318,22 @@
     }
 }
 
-void OpReorderer::defer(int viewportWidth, int viewportHeight, const DisplayList& displayList) {
+OpReorderer::OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList)
+        : mCanvasState(*this) {
     ATRACE_NAME("prepare drawing commands");
+
+    mLayerReorderers.emplace_back(viewportWidth, viewportHeight);
+    mLayerStack.push_back(0);
+
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             0, 0, viewportWidth, viewportHeight, Vector3());
     deferImpl(displayList);
 }
 
+void OpReorderer::onViewportInitialized() {}
+
+void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+
 /**
  * Used to define a list of lambdas referencing private OpReorderer::onXXXXOp() methods.
  *
@@ -348,15 +354,6 @@
     }
 }
 
-void OpReorderer::replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) {
-    ATRACE_NAME("flush drawing commands");
-    // Relay through layers in reverse order, since layers
-    // later in the list will be drawn by earlier ones
-    for (int i = mLayerReorderers.size() - 1; i >= 0; i--) {
-        mLayerReorderers[i].replayBakedOpsImpl(arg, receivers);
-    }
-}
-
 void OpReorderer::onRenderNodeOp(const RenderNodeOp& op) {
     if (op.renderNode->nothingToDraw()) {
         return;
@@ -405,15 +402,17 @@
 
 // TODO: test rejection at defer time, where the bounds become empty
 void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
+    const uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
+    const uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
+
     mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
     mCanvasState.writableSnapshot()->transform->loadIdentity();
-    mCanvasState.writableSnapshot()->initializeViewport(
-            (int) op.unmappedBounds.getWidth(), (int) op.unmappedBounds.getHeight());
+    mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
     mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
 
     // create a new layer, and push its index on the stack
     mLayerStack.push_back(mLayerReorderers.size());
-    mLayerReorderers.emplace_back();
+    mLayerReorderers.emplace_back(layerWidth, layerHeight);
     mLayerReorderers.back().beginLayerOp = &op;
 }
 
@@ -432,7 +431,8 @@
             beginLayerOp.unmappedBounds,
             beginLayerOp.localMatrix,
             beginLayerOp.localClipRect,
-            beginLayerOp.paint);
+            beginLayerOp.paint,
+            &mLayerReorderers[finishedLayerIndex].offscreenBuffer);
     BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
 
     if (bakedOpState) {
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 73dc9af..927ecfa 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -33,6 +33,7 @@
 class BakedOpState;
 class BatchBase;
 class MergingOpBatch;
+class OffscreenBuffer;
 class OpBatch;
 class Rect;
 
@@ -55,7 +56,7 @@
 }
 
 class OpReorderer : public CanvasStateClient {
-    typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpReceiver;
+    typedef std::function<void(void*, const RecordedOp&, const BakedOpState&)> BakedOpDispatcher;
 
     /**
      * Stores the deferred render operations and state used to compute ordering
@@ -63,6 +64,10 @@
      */
     class LayerReorderer {
     public:
+        LayerReorderer(uint32_t width, uint32_t height)
+                : width(width)
+                , height(height) {}
+
         // iterate back toward target to see if anything drawn since should overlap the new op
         // if no target, merging ops still iterate to find similar batch to insert after
         void locateInsertIndex(int batchId, const Rect& clippedBounds,
@@ -75,7 +80,11 @@
         void deferMergeableOp(LinearAllocator& allocator,
                 BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
 
-        void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers) const;
+        void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers) const;
+
+        bool empty() const {
+            return mBatches.empty();
+        }
 
         void clear() {
             mBatches.clear();
@@ -83,9 +92,12 @@
 
         void dump() const;
 
+        OffscreenBuffer* offscreenBuffer = nullptr;
         const BeginLayerOp* beginLayerOp = nullptr;
-
+        const uint32_t width;
+        const uint32_t height;
     private:
+
         std::vector<BatchBase*> mBatches;
 
         /**
@@ -100,14 +112,13 @@
 
     };
 public:
-    OpReorderer();
-    virtual ~OpReorderer() {}
-
     // TODO: not final, just presented this way for simplicity. Layers too?
-    void defer(const SkRect& clip, int viewportWidth, int viewportHeight,
+    OpReorderer(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
             const std::vector< sp<RenderNode> >& nodes);
 
-    void defer(int viewportWidth, int viewportHeight, const DisplayList& displayList);
+    OpReorderer(int viewportWidth, int viewportHeight, const DisplayList& displayList);
+
+    virtual ~OpReorderer() {}
 
     /**
      * replayBakedOps() is templated based on what class will receive ops being replayed.
@@ -117,20 +128,33 @@
      *
      * For example a BitmapOp would resolve, via the lambda lookup, to calling:
      *
-     * StaticReceiver::onBitmapOp(Arg* arg, const BitmapOp& op, const BakedOpState& state);
+     * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
      */
 #define BAKED_OP_RECEIVER(Type) \
-    [](void* internalArg, const RecordedOp& op, const BakedOpState& state) { \
-        StaticReceiver::on##Type(*(static_cast<Arg*>(internalArg)), static_cast<const Type&>(op), state); \
+    [](void* internalRenderer, const RecordedOp& op, const BakedOpState& state) { \
+        StaticDispatcher::on##Type(*(static_cast<Renderer*>(internalRenderer)), static_cast<const Type&>(op), state); \
     },
-    template <typename StaticReceiver, typename Arg>
-    void replayBakedOps(Arg& arg) {
-        static BakedOpReceiver receivers[] = {
+    template <typename StaticDispatcher, typename Renderer>
+    void replayBakedOps(Renderer& renderer) {
+        static BakedOpDispatcher receivers[] = {
             MAP_OPS(BAKED_OP_RECEIVER)
         };
-        StaticReceiver::startFrame(arg);
-        replayBakedOpsImpl((void*)&arg, receivers);
-        StaticReceiver::endFrame(arg);
+
+        // Relay through layers in reverse order, since layers
+        // later in the list will be drawn by earlier ones
+        for (int i = mLayerReorderers.size() - 1; i >= 1; i--) {
+            LayerReorderer& layer = mLayerReorderers[i];
+            if (!layer.empty()) {
+                layer.offscreenBuffer = renderer.startLayer(layer.width, layer.height);
+                layer.replayBakedOpsImpl((void*)&renderer, receivers);
+                renderer.endLayer();
+            }
+        }
+
+        const LayerReorderer& fbo0 = mLayerReorderers[0];
+        renderer.startFrame(fbo0.width, fbo0.height);
+        fbo0.replayBakedOpsImpl((void*)&renderer, receivers);
+        renderer.endFrame();
     }
 
     void dump() const {
@@ -155,7 +179,7 @@
 
     void deferImpl(const DisplayList& displayList);
 
-    void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
+    void replayBakedOpsImpl(void* arg, BakedOpDispatcher* receivers);
 
     /**
      * Declares all OpReorderer::onXXXXOp() methods for every RecordedOp type.
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index d4f65b6..8c3603b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -673,7 +673,7 @@
 
 bool OpenGLRenderer::createFboLayer(Layer* layer, Rect& bounds, Rect& clip) {
     layer->clipRect.set(clip);
-    layer->setFbo(mCaches.fboCache.get());
+    layer->setFbo(mRenderState.genFramebuffer());
 
     writableSnapshot()->region = &writableSnapshot()->layer->region;
     writableSnapshot()->flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index dd01637..7874d85 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -29,6 +29,7 @@
 namespace android {
 namespace uirenderer {
 
+class OffscreenBuffer;
 class RenderNode;
 struct Vertex;
 
@@ -136,8 +137,12 @@
 };
 
 struct LayerOp : RecordedOp {
-    LayerOp(BASE_PARAMS)
-            : SUPER(LayerOp) {}
+    LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
+            : SUPER(LayerOp)
+            , layerHandle(layerHandle) {}
+    // Records a handle to the Layer object, since the Layer itself won't be
+    // constructed until after this operation is constructed.
+    OffscreenBuffer** layerHandle;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index 1f113bc..273af3a 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -458,7 +458,7 @@
     // it to the bitmap pile
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
-    if (shader->asABitmap(&bitmap, nullptr, xy) == SkShader::kDefault_BitmapType) {
+    if (shader->isABitmap(&bitmap, nullptr, xy)) {
         refBitmap(bitmap);
         return;
     }
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 9c32b1a..454ee24 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -27,6 +27,8 @@
 #include "Snapshot.h"
 
 #include "SkDrawFilter.h"
+#include "SkPaint.h"
+#include "SkTLazy.h"
 #include <vector>
 
 namespace android {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 351fbaa..39cb8e9 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -16,13 +16,6 @@
 
 #include "RenderNode.h"
 
-#include <algorithm>
-#include <string>
-
-#include <SkCanvas.h>
-#include <algorithm>
-
-
 #include "DamageAccumulator.h"
 #include "Debug.h"
 #if HWUI_NEW_OPS
@@ -39,6 +32,12 @@
 #include "protos/hwui.pb.h"
 #include "protos/ProtoHelpers.h"
 
+#include <SkCanvas.h>
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+
 namespace android {
 namespace uirenderer {
 
@@ -79,6 +78,11 @@
     mNeedsDisplayListSync = true;
     delete mStagingDisplayList;
     mStagingDisplayList = displayList;
+    // If mParentCount == 0 we are the sole reference to this RenderNode,
+    // so immediately free the old display list
+    if (!mParentCount && !mStagingDisplayList) {
+        deleteDisplayList();
+    }
 }
 
 /**
@@ -250,7 +254,8 @@
 
     bool transformUpdateNeeded = false;
     if (!mLayer) {
-        mLayer = LayerRenderer::createRenderLayer(info.renderState, getWidth(), getHeight());
+        mLayer = LayerRenderer::createRenderLayer(
+                info.canvasContext.getRenderState(), getWidth(), getHeight());
         applyLayerPropertiesToLayer(info);
         damageSelf(info);
         transformUpdateNeeded = true;
@@ -269,9 +274,16 @@
     if (!mLayer) {
         Caches::getInstance().dumpMemoryUsage();
         if (info.errorHandler) {
-            std::string msg = "Unable to create layer for ";
-            msg += getName();
-            info.errorHandler->onError(msg);
+            std::ostringstream err;
+            err << "Unable to create layer for " << getName();
+            const int maxTextureSize = Caches::getInstance().maxTextureSize;
+            if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) {
+                err << ", size " << getWidth() << "x" << getHeight()
+                        << " exceeds max size " << maxTextureSize;
+            } else {
+                err << ", see logcat for more info";
+            }
+            info.errorHandler->onError(err.str());
         }
         return;
     }
@@ -293,12 +305,10 @@
         info.renderer->pushLayerUpdate(mLayer);
     }
 
-    if (info.canvasContext) {
-        // There might be prefetched layers that need to be accounted for.
-        // That might be us, so tell CanvasContext that this layer is in the
-        // tree and should not be destroyed.
-        info.canvasContext->markLayerInUse(this);
-    }
+    // There might be prefetched layers that need to be accounted for.
+    // That might be us, so tell CanvasContext that this layer is in the
+    // tree and should not be destroyed.
+    info.canvasContext.markLayerInUse(this);
 }
 
 /**
@@ -419,7 +429,8 @@
         TextureCache& cache = Caches::getInstance().textureCache;
         info.out.hasFunctors |= subtree->getFunctors().size();
         for (auto&& bitmapResource : subtree->getBitmapResources()) {
-            info.prepareTextures = cache.prefetchAndMarkInUse(info.canvasContext, bitmapResource);
+            void* ownerToken = &info.canvasContext;
+            info.prepareTextures = cache.prefetchAndMarkInUse(ownerToken, bitmapResource);
         }
         for (auto&& op : subtree->getChildren()) {
             RenderNode* childNode = op->renderNode;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 36633b5..a8f8134 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -194,15 +194,13 @@
 
 void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
     SkCanvas* newCanvas = new SkCanvas(bitmap);
-    SkASSERT(newCanvas);
 
     if (!bitmap.isNull()) {
         // Copy the canvas matrix & clip state.
         newCanvas->setMatrix(mCanvas->getTotalMatrix());
-        if (NULL != mCanvas->getDevice() && NULL != newCanvas->getDevice()) {
-            ClipCopier copier(newCanvas);
-            mCanvas->replayClips(&copier);
-        }
+
+        ClipCopier copier(newCanvas);
+        mCanvas->replayClips(&copier);
     }
 
     // unrefs the existing canvas
@@ -217,15 +215,15 @@
 // ----------------------------------------------------------------------------
 
 bool SkiaCanvas::isOpaque() {
-    return mCanvas->getDevice()->accessBitmap(false).isOpaque();
+    return mCanvas->imageInfo().isOpaque();
 }
 
 int SkiaCanvas::width() {
-    return mCanvas->getBaseLayerSize().width();
+    return mCanvas->imageInfo().width();
 }
 
 int SkiaCanvas::height() {
-    return mCanvas->getBaseLayerSize().height();
+    return mCanvas->imageInfo().height();
 }
 
 // ----------------------------------------------------------------------------
@@ -581,7 +579,7 @@
                             float dstRight, float dstBottom, const SkPaint* paint) {
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    mCanvas->drawBitmapRectToRect(bitmap, &srcRect, dstRect, paint);
+    mCanvas->drawBitmapRect(bitmap, srcRect, dstRect, paint);
 }
 
 void SkiaCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index c3f5eb2..2d5f70f 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -125,7 +125,7 @@
 }
 
 void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* srcPtr,
-        const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags) {
+        const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
     SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(bitmap.width(), bitmap.height());
     // TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
     mCanvas->drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index 0de9650..2fe4327 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -63,7 +63,7 @@
     virtual void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top,
                               const SkPaint*) override;
     virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
-                                  const SkPaint* paint, DrawBitmapRectFlags flags) override;
+                                  const SkPaint* paint, SrcRectConstraint) override;
     virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                   const SkRect& dst, const SkPaint*) override;
     virtual void onDrawSprite(const SkBitmap&, int left, int top,
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 6c105cf..83652c6 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -204,7 +204,7 @@
         SkiaShaderData::BitmapShaderData* outData) {
     SkBitmap bitmap;
     SkShader::TileMode xy[2];
-    if (shader.asABitmap(&bitmap, nullptr, xy) != SkShader::kDefault_BitmapType) {
+    if (!shader.isABitmap(&bitmap, nullptr, xy)) {
         return false;
     }
 
@@ -272,7 +272,7 @@
     }
 
     // The shader is not a gradient. Check for a bitmap shader.
-    if (shader.asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
+    if (shader.isABitmap()) {
         return kBitmap_SkiaShaderType;
     }
     return kNone_SkiaShaderType;
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 12a3e76..0835c29 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -217,7 +217,7 @@
     }
 }
 
-static void tessellateShadows(
+void tessellateShadows(
         const Matrix4* drawTransform, const Rect* localClip,
         bool isCasterOpaque, const SkPath* casterPerimeter,
         const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index b54666b..06e567e 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -17,16 +17,22 @@
 #ifndef ANDROID_HWUI_TESSELLATION_CACHE_H
 #define ANDROID_HWUI_TESSELLATION_CACHE_H
 
-#include <utils/LruCache.h>
-#include <utils/Mutex.h>
-
 #include "Debug.h"
+#include "Matrix.h"
+#include "Rect.h"
+#include "Vector.h"
+#include "thread/TaskProcessor.h"
 #include "utils/Macros.h"
 #include "utils/Pair.h"
 
+#include <SkPaint.h>
+
+#include <utils/LruCache.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+
 class SkBitmap;
 class SkCanvas;
-class SkPaint;
 class SkPath;
 struct SkRect;
 
@@ -185,6 +191,13 @@
 
 }; // class TessellationCache
 
+void tessellateShadows(
+        const Matrix4* drawTransform, const Rect* localClip,
+        bool isCasterOpaque, const SkPath* casterPerimeter,
+        const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
+        const Vector3& lightCenter, float lightRadius,
+        VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
+
 }; // namespace uirenderer
 }; // namespace android
 
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index 98e6146..1c31487 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -55,70 +55,46 @@
         MODE_RT_ONLY,
     };
 
-    explicit TreeInfo(TraversalMode mode, RenderState& renderState)
-        : mode(mode)
-        , prepareTextures(mode == MODE_FULL)
-        , runAnimations(true)
-        , damageAccumulator(nullptr)
-        , renderState(renderState)
-        , renderer(nullptr)
-        , errorHandler(nullptr)
-        , canvasContext(nullptr)
-    {}
-
-    explicit TreeInfo(TraversalMode mode, const TreeInfo& clone)
-        : mode(mode)
-        , prepareTextures(mode == MODE_FULL)
-        , runAnimations(clone.runAnimations)
-        , damageAccumulator(clone.damageAccumulator)
-        , renderState(clone.renderState)
-        , renderer(clone.renderer)
-        , errorHandler(clone.errorHandler)
-        , canvasContext(clone.canvasContext)
+    TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
+            : mode(mode)
+            , prepareTextures(mode == MODE_FULL)
+            , canvasContext(canvasContext)
     {}
 
     TraversalMode mode;
     // TODO: Remove this? Currently this is used to signal to stop preparing
     // textures if we run out of cache space.
     bool prepareTextures;
+    renderthread::CanvasContext& canvasContext;
     // TODO: buildLayer uses this to suppress running any animations, but this
     // should probably be refactored somehow. The reason this is done is
     // because buildLayer is not setup for injecting the animationHook, as well
     // as this being otherwise wasted work as all the animators will be
     // re-evaluated when the frame is actually drawn
-    bool runAnimations;
+    bool runAnimations = true;
 
     // Must not be null during actual usage
-    DamageAccumulator* damageAccumulator;
-    RenderState& renderState;
+    DamageAccumulator* damageAccumulator = nullptr;
     // The renderer that will be drawing the next frame. Use this to push any
     // layer updates or similar. May be NULL.
-    OpenGLRenderer* renderer;
-    ErrorHandler* errorHandler;
-    // May be NULL (TODO: can it really?)
-    renderthread::CanvasContext* canvasContext;
+    OpenGLRenderer* renderer = nullptr;
+    ErrorHandler* errorHandler = nullptr;
 
     struct Out {
-        Out()
-            : hasFunctors(false)
-            , hasAnimations(false)
-            , requiresUiRedraw(false)
-            , canDrawThisFrame(true)
-        {}
-        bool hasFunctors;
+        bool hasFunctors = false;
         // This is only updated if evaluateAnimations is true
-        bool hasAnimations;
+        bool hasAnimations = false;
         // This is set to true if there is an animation that RenderThread cannot
         // animate itself, such as if hasFunctors is true
         // This is only set if hasAnimations is true
-        bool requiresUiRedraw;
+        bool requiresUiRedraw = false;
         // This is set to true if draw() can be called this frame
         // false means that we must delay until the next vsync pulse as frame
         // production is outrunning consumption
         // NOTE that if this is false CanvasContext will set either requiresUiRedraw
         // *OR* will post itself for the next vsync automatically, use this
         // only to avoid calling draw()
-        bool canDrawThisFrame;
+        bool canDrawThisFrame = true;
     } out;
 
     // TODO: Damage calculations
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 7c3f2fd..6367dbd 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -135,8 +135,8 @@
     }
 
 
-    void dump() {
-        ALOGD("Vector3[%.2f, %.2f, %.2f]", x, y, z);
+    void dump(const char* label = "Vector3") const {
+        ALOGD("%s[%.2f, %.2f, %.2f]", label, x, y, z);
     }
 };
 
diff --git a/libs/hwui/microbench/OpReordererBench.cpp b/libs/hwui/microbench/OpReordererBench.cpp
index cf96d44..43f170f 100644
--- a/libs/hwui/microbench/OpReordererBench.cpp
+++ b/libs/hwui/microbench/OpReordererBench.cpp
@@ -48,8 +48,7 @@
 void BM_OpReorderer_defer::Run(int iters) {
     StartBenchmarkTiming();
     for (int i = 0; i < iters; i++) {
-        OpReorderer reorderer;
-        reorderer.defer(200, 200, *sReorderingDisplayList);
+        OpReorderer reorderer(200, 200, *sReorderingDisplayList);
         MicroBench::DoNotOptimize(&reorderer);
     }
     StopBenchmarkTiming();
@@ -60,12 +59,11 @@
     TestUtils::runOnRenderThread([this, iters](RenderState& renderState, Caches& caches) {
         StartBenchmarkTiming();
         for (int i = 0; i < iters; i++) {
-            OpReorderer reorderer;
-            reorderer.defer(200, 200, *sReorderingDisplayList);
-            MicroBench::DoNotOptimize(&reorderer);
+            OpReorderer reorderer(200, 200, *sReorderingDisplayList);
 
-            BakedOpRenderer::Info info(caches, renderState, 200, 200, true);
-            reorderer.replayBakedOps<BakedOpRenderer>(info);
+            BakedOpRenderer renderer(caches, renderState, true);
+            reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
+            MicroBench::DoNotOptimize(&renderer);
         }
         StopBenchmarkTiming();
     });
diff --git a/libs/hwui/microbench/ShadowBench.cpp b/libs/hwui/microbench/ShadowBench.cpp
new file mode 100644
index 0000000..1b0f5ea
--- /dev/null
+++ b/libs/hwui/microbench/ShadowBench.cpp
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/Benchmark.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "Vector.h"
+#include "VertexBuffer.h"
+#include "TessellationCache.h"
+#include "microbench/MicroBench.h"
+
+#include <SkPath.h>
+
+#include <memory>
+
+using namespace android;
+using namespace android::uirenderer;
+
+struct ShadowTestData {
+    Matrix4 drawTransform;
+    Rect localClip;
+    Matrix4 casterTransformXY;
+    Matrix4 casterTransformZ;
+    Vector3 lightCenter;
+    float lightRadius;
+};
+
+void createShadowTestData(ShadowTestData* out) {
+    static float SAMPLE_DRAW_TRANSFORM[] = {
+            1, 0, 0, 0,
+            0, 1, 0, 0,
+            0, 0, 1, 0,
+            0, 0, 0, 1,
+    };
+    static float SAMPLE_CASTERXY[] = {
+            1, 0, 0, 0,
+            0, 1, 0, 0,
+            0, 0, 1, 0,
+            32, 32, 0, 1,
+    };
+    static float SAMPLE_CASTERZ[] = {
+            1, 0, 0, 0,
+            0, 1, 0, 0,
+            0, 0, 1, 0,
+            32, 32, 32, 1,
+    };
+    static Rect SAMPLE_CLIP(0, 0, 1536, 2048);
+    static Vector3 SAMPLE_LIGHT_CENTER{768, -400, 1600};
+    static float SAMPLE_LIGHT_RADIUS = 1600;
+
+    out->drawTransform.load(SAMPLE_DRAW_TRANSFORM);
+    out->localClip = SAMPLE_CLIP;
+    out->casterTransformXY.load(SAMPLE_CASTERXY);
+    out->casterTransformZ.load(SAMPLE_CASTERZ);
+    out->lightCenter = SAMPLE_LIGHT_CENTER;
+    out->lightRadius = SAMPLE_LIGHT_RADIUS;
+}
+
+static inline void tessellateShadows(ShadowTestData& testData, bool opaque,
+        const SkPath& shape, VertexBuffer* ambient, VertexBuffer* spot) {
+    tessellateShadows(&testData.drawTransform, &testData.localClip,
+            opaque, &shape, &testData.casterTransformXY,
+            &testData.casterTransformZ, testData.lightCenter,
+            testData.lightRadius, *ambient, *spot);
+}
+
+BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_opaque);
+void BM_TessellateShadows_roundrect_opaque::Run(int iters) {
+    ShadowTestData shadowData;
+    createShadowTestData(&shadowData);
+    SkPath path;
+    path.addRoundRect(SkRect::MakeWH(100, 100), 5, 5);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        VertexBuffer ambient;
+        VertexBuffer spot;
+        tessellateShadows(shadowData, true, path, &ambient, &spot);
+        MicroBench::DoNotOptimize(&ambient);
+        MicroBench::DoNotOptimize(&spot);
+    }
+    StopBenchmarkTiming();
+}
+
+BENCHMARK_NO_ARG(BM_TessellateShadows_roundrect_translucent);
+void BM_TessellateShadows_roundrect_translucent::Run(int iters) {
+    ShadowTestData shadowData;
+    createShadowTestData(&shadowData);
+    SkPath path;
+    path.reset();
+    path.addRoundRect(SkRect::MakeLTRB(0, 0, 100, 100), 5, 5);
+
+    StartBenchmarkTiming();
+    for (int i = 0; i < iters; i++) {
+        std::unique_ptr<VertexBuffer> ambient(new VertexBuffer);
+        std::unique_ptr<VertexBuffer> spot(new VertexBuffer);
+        tessellateShadows(shadowData, false, path, ambient.get(), spot.get());
+        MicroBench::DoNotOptimize(ambient.get());
+        MicroBench::DoNotOptimize(spot.get());
+    }
+    StopBenchmarkTiming();
+}
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index dfa70ac..9637117 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -125,6 +125,21 @@
     }
 }
 
+GLuint RenderState::genFramebuffer() {
+    GLuint ret;
+    glGenFramebuffers(1, &ret);
+    return ret;
+}
+
+void RenderState::deleteFramebuffer(GLuint fbo) {
+    if (mFramebuffer == fbo) {
+        // GL defines that deleting the currently bound FBO rebinds FBO 0.
+        // Reflect this in our cached value.
+        mFramebuffer = 0;
+    }
+    glDeleteFramebuffers(1, &fbo);
+}
+
 void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) {
     if (mode == DrawGlInfo::kModeProcessNoContext) {
         // If there's no context we don't need to interrupt as there's
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 9ae0845..3cda170 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -16,24 +16,25 @@
 #ifndef RENDERSTATE_H
 #define RENDERSTATE_H
 
-#include <set>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-#include <utils/Mutex.h>
-#include <utils/Functor.h>
-#include <utils/RefBase.h>
-#include <private/hwui/DrawGlInfo.h>
-#include <renderstate/Blend.h>
-
 #include "AssetAtlas.h"
 #include "Caches.h"
 #include "Glop.h"
+#include "renderstate/Blend.h"
 #include "renderstate/MeshState.h"
 #include "renderstate/PixelBufferState.h"
 #include "renderstate/Scissor.h"
 #include "renderstate/Stencil.h"
 #include "utils/Macros.h"
 
+#include <set>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <ui/Region.h>
+#include <utils/Mutex.h>
+#include <utils/Functor.h>
+#include <utils/RefBase.h>
+#include <private/hwui/DrawGlInfo.h>
+
 namespace android {
 namespace uirenderer {
 
@@ -49,6 +50,8 @@
 // wrapper of Caches for users to migrate to.
 class RenderState {
     PREVENT_COPY_AND_ASSIGN(RenderState);
+    friend class renderthread::RenderThread;
+    friend class Caches;
 public:
     void onGLContextCreated();
     void onGLContextDestroyed();
@@ -57,7 +60,9 @@
     void getViewport(GLsizei* outWidth, GLsizei* outHeight);
 
     void bindFramebuffer(GLuint fbo);
-    GLint getFramebuffer() { return mFramebuffer; }
+    GLuint getFramebuffer() { return mFramebuffer; }
+    GLuint genFramebuffer();
+    void deleteFramebuffer(GLuint fbo);
 
     void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info);
 
@@ -93,10 +98,8 @@
     Stencil& stencil() { return *mStencil; }
 
     void dump();
-private:
-    friend class renderthread::RenderThread;
-    friend class Caches;
 
+private:
     void interruptForFunctorInvoke();
     void resumeFromFunctorInvoke();
     void assertOnGLThread();
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index f571426..c1f6670 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -27,6 +27,7 @@
 #include "renderstate/RenderState.h"
 #include "renderstate/Stencil.h"
 #include "protos/hwui.pb.h"
+#include "utils/TimeUtils.h"
 
 #if HWUI_NEW_OPS
 #include "BakedOpRenderer.h"
@@ -108,6 +109,7 @@
         const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer);
         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
         mHaveNewSurface = true;
+        mSwapHistory.clear();
         makeCurrent();
     } else {
         mRenderThread.removeFrameCallback(this);
@@ -197,7 +199,6 @@
 
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
-    info.canvasContext = this;
 
     mAnimationContext->startFrame(info.mode);
     for (const sp<RenderNode>& node : mRenderNodes) {
@@ -217,13 +218,30 @@
         return;
     }
 
-    int runningBehind = 0;
-    // TODO: This query is moderately expensive, investigate adding some sort
-    // of fast-path based off when we last called eglSwapBuffers() as well as
-    // last vsync time. Or something.
-    mNativeWindow->query(mNativeWindow.get(),
-            NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
-    info.out.canDrawThisFrame = !runningBehind;
+    if (CC_LIKELY(mSwapHistory.size())) {
+        nsecs_t latestVsync = mRenderThread.timeLord().latestVsync();
+        const SwapHistory& lastSwap = mSwapHistory.back();
+        int vsyncDelta = std::abs(lastSwap.vsyncTime - latestVsync);
+        // The slight fudge-factor is to deal with cases where
+        // the vsync was estimated due to being slow handling the signal.
+        // See the logic in TimeLord#computeFrameTimeNanos or in
+        // Choreographer.java for details on when this happens
+        if (vsyncDelta < 2_ms) {
+            // Already drew for this vsync pulse, UI draw request missed
+            // the deadline for RT animations
+            info.out.canDrawThisFrame = false;
+        } else if (lastSwap.swapTime < latestVsync) {
+            info.out.canDrawThisFrame = true;
+        } else {
+            // We're maybe behind? Find out for sure
+            int runningBehind = 0;
+            mNativeWindow->query(mNativeWindow.get(),
+                    NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND, &runningBehind);
+            info.out.canDrawThisFrame = !runningBehind;
+        }
+    } else {
+        info.out.canDrawThisFrame = true;
+    }
 
     if (!info.out.canDrawThisFrame) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
@@ -266,11 +284,11 @@
 
     Frame frame = mEglManager.beginFrame(mEglSurface);
 
-    if (frame.width() != lastFrameWidth || frame.height() != lastFrameHeight) {
+    if (frame.width() != mLastFrameWidth || frame.height() != mLastFrameHeight) {
         // can't rely on prior content of window if viewport size changes
         dirty.setEmpty();
-        lastFrameWidth = frame.width();
-        lastFrameHeight = frame.height();
+        mLastFrameWidth = frame.width();
+        mLastFrameHeight = frame.height();
     } else if (mHaveNewSurface || frame.bufferAge() == 0) {
         // New surface needs a full draw
         dirty.setEmpty();
@@ -297,7 +315,7 @@
     // last frame so there's nothing to union() against
     // Therefore we only care about the > 1 case.
     if (frame.bufferAge() > 1) {
-        if (frame.bufferAge() > (int) mDamageHistory.size()) {
+        if (frame.bufferAge() > (int) mSwapHistory.size()) {
             // We don't have enough history to handle this old of a buffer
             // Just do a full-draw
             dirty.set(0, 0, frame.width(), frame.height());
@@ -305,49 +323,46 @@
             // At this point we haven't yet added the latest frame
             // to the damage history (happens below)
             // So we need to damage
-            for (int i = mDamageHistory.size() - 1;
-                    i > ((int) mDamageHistory.size()) - frame.bufferAge(); i--) {
-                dirty.join(mDamageHistory[i]);
+            for (int i = mSwapHistory.size() - 1;
+                    i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
+                dirty.join(mSwapHistory[i].damage);
             }
         }
     }
 
-    // Add the screen damage to the ring buffer.
-    mDamageHistory.next() = screenDirty;
-
     mEglManager.damageFrame(frame, dirty);
 
 #if HWUI_NEW_OPS
-    OpReorderer reorderer;
-    reorderer.defer(dirty, frame.width(), frame.height(), mRenderNodes);
-    BakedOpRenderer::Info info(Caches::getInstance(), mRenderThread.renderState(),
-            frame.width(), frame.height(), mOpaque);
+    OpReorderer reorderer(dirty, frame.width(), frame.height(), mRenderNodes);
+    BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(), mOpaque);
     // TODO: profiler().draw(mCanvas);
-    reorderer.replayBakedOps<BakedOpRenderer>(info);
+    reorderer.replayBakedOps<BakedOpDispatcher>(renderer);
 
-    bool drew = info.didDraw;
+    bool drew = renderer.didDraw();
 
 #else
     mCanvas->prepareDirty(frame.width(), frame.height(),
             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
 
     Rect outBounds;
-    // It there are multiple render nodes, they are as follows:
-    // #0 - backdrop
+    // It there are multiple render nodes, they are laid out as follows:
+    // #0 - backdrop (content + caption)
     // #1 - content (positioned at (0,0) and clipped to - its bounds mContentDrawBounds)
-    // #2 - frame
+    // #2 - additional overlay nodes
     // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
     // resizing however it might become partially visible. The following render loop will crop the
-    // backdrop against the content and draw the remaining part of it. It will then crop the content
-    // against the backdrop (since that indicates a shrinking of the window) and then the frame
-    // around everything.
+    // backdrop against the content and draw the remaining part of it. It will then draw the content
+    // cropped to the backdrop (since that indicates a shrinking of the window).
+    //
+    // Additional nodes will be drawn on top with no particular clipping semantics.
+
     // The bounds of the backdrop against which the content should be clipped.
     Rect backdropBounds = mContentDrawBounds;
     // Usually the contents bounds should be mContentDrawBounds - however - we will
     // move it towards the fixed edge to give it a more stable appearance (for the moment).
     Rect contentBounds;
     // If there is no content bounds we ignore the layering as stated above and start with 2.
-    int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() <= 2) ? 2 : 0;
+    int layer = (mContentDrawBounds.isEmpty() || mRenderNodes.size() == 1) ? 2 : 0;
     // Draw all render nodes. Note that
     for (const sp<RenderNode>& node : mRenderNodes) {
         if (layer == 0) { // Backdrop.
@@ -424,6 +439,7 @@
             const float dy = backdropBounds.top - top;
             const float width = backdropBounds.getWidth();
             const float height = backdropBounds.getHeight();
+
             mCanvas->translate(dx, dy);
             if (mCanvas->clipRect(left, top, left + width, top + height, SkRegion::kIntersect_Op)) {
                 mCanvas->drawRenderNode(node.get(), outBounds);
@@ -447,6 +463,10 @@
         if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
             setSurface(nullptr);
         }
+        SwapHistory& swap = mSwapHistory.next();
+        swap.damage = screenDirty;
+        swap.swapTime = systemTime(CLOCK_MONOTONIC);
+        swap.vsyncTime = mRenderThread.timeLord().latestVsync();
         mHaveNewSurface = false;
     }
 
@@ -489,7 +509,7 @@
         .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
                 mRenderThread.timeLord().latestVsync());
 
-    TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
+    TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
     prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
     if (info.out.canDrawThisFrame) {
         draw();
@@ -533,7 +553,7 @@
     // buildLayer() will leave the tree in an unknown state, so we must stop drawing
     stopDrawing();
 
-    TreeInfo info(TreeInfo::MODE_FULL, mRenderThread.renderState());
+    TreeInfo info(TreeInfo::MODE_FULL, *this);
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
     info.runAnimations = false;
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 16956e6..30e6562 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -130,6 +130,10 @@
         mContentDrawBounds.set(left, top, right, bottom);
     }
 
+    RenderState& getRenderState() {
+        return mRenderThread.renderState();
+    }
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -141,8 +145,8 @@
 
     void freePrefetechedLayers();
 
-    int lastFrameWidth = 0;
-    int lastFrameHeight = 0;
+    EGLint mLastFrameWidth = 0;
+    EGLint mLastFrameHeight = 0;
 
     RenderThread& mRenderThread;
     EglManager& mEglManager;
@@ -150,7 +154,13 @@
     EGLSurface mEglSurface = EGL_NO_SURFACE;
     bool mBufferPreserved = false;
     SwapBehavior mSwapBehavior = kSwap_default;
-    RingBuffer<SkRect, 3> mDamageHistory;
+    struct SwapHistory {
+        SkRect damage;
+        nsecs_t vsyncTime;
+        nsecs_t swapTime;
+    };
+
+    RingBuffer<SwapHistory, 3> mSwapHistory;
 
     bool mOpaque;
     OpenGLRenderer* mCanvas = nullptr;
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index a47c9ec..ab860c7 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -87,7 +87,7 @@
     bool canUnblockUiThread;
     bool canDrawThisFrame;
     {
-        TreeInfo info(TreeInfo::MODE_FULL, mRenderThread->renderState());
+        TreeInfo info(TreeInfo::MODE_FULL, *mContext);
         canUnblockUiThread = syncFrameState(info);
         canDrawThisFrame = info.out.canDrawThisFrame;
     }
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index b353ae6..485759b 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -333,7 +333,7 @@
     if (CC_LIKELY(err == EGL_SUCCESS)) {
         return true;
     }
-    if (err == EGL_BAD_SURFACE) {
+    if (err == EGL_BAD_SURFACE || err == EGL_BAD_NATIVE_WINDOW) {
         // For some reason our surface was destroyed out from under us
         // This really shouldn't happen, but if it does we can recover easily
         // by just not trying to use the surface anymore
diff --git a/libs/hwui/tests/TreeContentAnimation.cpp b/libs/hwui/tests/TreeContentAnimation.cpp
index 891af91..2eefd37 100644
--- a/libs/hwui/tests/TreeContentAnimation.cpp
+++ b/libs/hwui/tests/TreeContentAnimation.cpp
@@ -54,15 +54,10 @@
     }
 };
 
-static TestCanvas* startRecording(RenderNode* node) {
-    TestCanvas* renderer = new TestCanvas(
-            node->stagingProperties().getWidth(), node->stagingProperties().getHeight());
-    return renderer;
-}
-
-static void endRecording(TestCanvas* renderer, RenderNode* node) {
-    node->setStagingDisplayList(renderer->finishRecording());
-    delete renderer;
+static void recordNode(RenderNode& node, std::function<void(TestCanvas&)> contentCallback) {
+    TestCanvas canvas(node.stagingProperties().getWidth(), node.stagingProperties().getHeight());
+    contentCallback(canvas);
+    node.setStagingDisplayList(canvas.finishRecording());
 }
 
 class TreeContentAnimation {
@@ -75,7 +70,7 @@
             frameCount = fc;
         }
     }
-    virtual void createContent(int width, int height, TestCanvas* renderer) = 0;
+    virtual void createContent(int width, int height, TestCanvas* canvas) = 0;
     virtual void doFrame(int frameNr) = 0;
 
     template <class T>
@@ -108,11 +103,9 @@
         proxy->setup(width, height, dp(800.0f), 255 * 0.075, 255 * 0.15);
         proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
 
-        android::uirenderer::Rect DUMMY;
-
-        TestCanvas* renderer = startRecording(rootNode);
-        animation.createContent(width, height, renderer);
-        endRecording(renderer, rootNode);
+        recordNode(*rootNode, [&animation, width, height](TestCanvas& canvas) {
+            animation.createContent(width, height, &canvas); //TODO: no&
+        });
 
         // Do a few cold runs then reset the stats so that the caches are all hot
         for (int i = 0; i < 3; i++) {
@@ -140,19 +133,19 @@
 class ShadowGridAnimation : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, TestCanvas* renderer) override {
-        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-        renderer->insertReorderBarrier(true);
+    void createContent(int width, int height, TestCanvas* canvas) override {
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas->insertReorderBarrier(true);
 
         for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
             for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
                 sp<RenderNode> card = createCard(x, y, dp(100), dp(100));
-                renderer->drawRenderNode(card.get());
+                canvas->drawRenderNode(card.get());
                 cards.push_back(card);
             }
         }
 
-        renderer->insertReorderBarrier(false);
+        canvas->insertReorderBarrier(false);
     }
     void doFrame(int frameNr) override {
         int curFrame = frameNr % 150;
@@ -171,9 +164,9 @@
         node->mutateStagingProperties().mutableOutline().setShouldClip(true);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
 
-        TestCanvas* renderer = startRecording(node.get());
-        renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
-        endRecording(renderer, node.get());
+        recordNode(*node, [](TestCanvas& canvas) {
+            canvas.drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+        });
         return node;
     }
 };
@@ -187,19 +180,19 @@
 class ShadowGrid2Animation : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, TestCanvas* renderer) override {
-        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-        renderer->insertReorderBarrier(true);
+    void createContent(int width, int height, TestCanvas* canvas) override {
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas->insertReorderBarrier(true);
 
         for (int x = dp(8); x < (width - dp(58)); x += dp(58)) {
             for (int y = dp(8); y < (height - dp(58)); y += dp(58)) {
                 sp<RenderNode> card = createCard(x, y, dp(50), dp(50));
-                renderer->drawRenderNode(card.get());
+                canvas->drawRenderNode(card.get());
                 cards.push_back(card);
             }
         }
 
-        renderer->insertReorderBarrier(false);
+        canvas->insertReorderBarrier(false);
     }
     void doFrame(int frameNr) override {
         int curFrame = frameNr % 150;
@@ -218,9 +211,9 @@
         node->mutateStagingProperties().mutableOutline().setShouldClip(true);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z);
 
-        TestCanvas* renderer = startRecording(node.get());
-        renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
-        endRecording(renderer, node.get());
+        recordNode(*node, [](TestCanvas& canvas) {
+            canvas.drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode);
+        });
         return node;
     }
 };
@@ -233,15 +226,30 @@
 
 class RectGridAnimation : public TreeContentAnimation {
 public:
-    sp<RenderNode> card;
-    void createContent(int width, int height, TestCanvas* renderer) override {
-        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-        renderer->insertReorderBarrier(true);
+    sp<RenderNode> card = new RenderNode();
+    void createContent(int width, int height, TestCanvas* canvas) override {
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas->insertReorderBarrier(true);
 
-        card = createCard(40, 40, 200, 200);
-        renderer->drawRenderNode(card.get());
+        card->mutateStagingProperties().setLeftTopRightBottom(50, 50, 250, 250);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        recordNode(*card, [](TestCanvas& canvas) {
+            canvas.drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
 
-        renderer->insertReorderBarrier(false);
+            SkRegion region;
+            for (int xOffset = 0; xOffset < 200; xOffset+=2) {
+                for (int yOffset = 0; yOffset < 200; yOffset+=2) {
+                    region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
+                }
+            }
+
+            SkPaint paint;
+            paint.setColor(0xff00ffff);
+            canvas.drawRegion(region, paint);
+        });
+        canvas->drawRenderNode(card.get());
+
+        canvas->insertReorderBarrier(false);
     }
     void doFrame(int frameNr) override {
         int curFrame = frameNr % 150;
@@ -249,29 +257,6 @@
         card->mutateStagingProperties().setTranslationY(curFrame);
         card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
     }
-private:
-    sp<RenderNode> createCard(int x, int y, int width, int height) {
-        sp<RenderNode> node = new RenderNode();
-        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
-        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-
-        TestCanvas* renderer = startRecording(node.get());
-        renderer->drawColor(0xFFFF00FF, SkXfermode::kSrcOver_Mode);
-
-        SkRegion region;
-        for (int xOffset = 0; xOffset < width; xOffset+=2) {
-            for (int yOffset = 0; yOffset < height; yOffset+=2) {
-                region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
-            }
-        }
-
-        SkPaint paint;
-        paint.setColor(0xff00ffff);
-        renderer->drawRegion(region, paint);
-
-        endRecording(renderer, node.get());
-        return node;
-    }
 };
 static Benchmark _RectGrid(BenchmarkInfo{
     "rectgrid",
@@ -282,15 +267,22 @@
 
 class OvalAnimation : public TreeContentAnimation {
 public:
-    sp<RenderNode> card;
-    void createContent(int width, int height, TestCanvas* renderer) override {
-        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
-        renderer->insertReorderBarrier(true);
+    sp<RenderNode> card = new RenderNode();
+    void createContent(int width, int height, TestCanvas* canvas) override {
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas->insertReorderBarrier(true);
 
-        card = createCard(40, 40, 400, 400);
-        renderer->drawRenderNode(card.get());
+        card->mutateStagingProperties().setLeftTopRightBottom(0, 0, 200, 200);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        recordNode(*card, [](TestCanvas& canvas) {
+            SkPaint paint;
+            paint.setAntiAlias(true);
+            paint.setColor(0xFF000000);
+            canvas.drawOval(0, 0, 200, 200, paint);
+        });
+        canvas->drawRenderNode(card.get());
 
-        renderer->insertReorderBarrier(false);
+        canvas->insertReorderBarrier(false);
     }
 
     void doFrame(int frameNr) override {
@@ -299,22 +291,6 @@
         card->mutateStagingProperties().setTranslationY(curFrame);
         card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
     }
-private:
-    sp<RenderNode> createCard(int x, int y, int width, int height) {
-        sp<RenderNode> node = new RenderNode();
-        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
-        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-
-        TestCanvas* renderer = startRecording(node.get());
-
-        SkPaint paint;
-        paint.setAntiAlias(true);
-        paint.setColor(0xFF000000);
-        renderer->drawOval(0, 0, width, height, paint);
-
-        endRecording(renderer, node.get());
-        return node;
-    }
 };
 static Benchmark _Oval(BenchmarkInfo{
     "oval",
@@ -325,7 +301,7 @@
 class PartialDamageTest : public TreeContentAnimation {
 public:
     std::vector< sp<RenderNode> > cards;
-    void createContent(int width, int height, TestCanvas* renderer) override {
+    void createContent(int width, int height, TestCanvas* canvas) override {
         static SkColor COLORS[] = {
                 0xFFF44336,
                 0xFF9C27B0,
@@ -333,13 +309,13 @@
                 0xFF4CAF50,
         };
 
-        renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode);
 
         for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
             for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
                 sp<RenderNode> card = createCard(x, y, dp(100), dp(100),
                         COLORS[static_cast<int>((y / dp(116))) % 4]);
-                renderer->drawRenderNode(card.get());
+                canvas->drawRenderNode(card.get());
                 cards.push_back(card);
             }
         }
@@ -350,10 +326,10 @@
         cards[0]->mutateStagingProperties().setTranslationY(curFrame);
         cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        TestCanvas* renderer = startRecording(cards[0].get());
-        renderer->drawColor(interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0),
-                SkXfermode::kSrcOver_Mode);
-        endRecording(renderer, cards[0].get());
+        recordNode(*cards[0], [curFrame](TestCanvas& canvas) {
+            canvas.drawColor(interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0),
+                    SkXfermode::kSrcOver_Mode);
+        });
     }
 
     static SkColor interpolateColor(float fraction, SkColor start, SkColor end) {
@@ -378,9 +354,9 @@
         node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
         node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
 
-        TestCanvas* renderer = startRecording(node.get());
-        renderer->drawColor(color, SkXfermode::kSrcOver_Mode);
-        endRecording(renderer, node.get());
+        recordNode(*node, [color](TestCanvas& canvas) {
+            canvas.drawColor(color, SkXfermode::kSrcOver_Mode);
+        });
         return node;
     }
 };
@@ -393,16 +369,24 @@
 });
 
 
-class SimpleRectGridAnimation : public TreeContentAnimation {
+class SaveLayerAnimation : public TreeContentAnimation {
 public:
-    sp<RenderNode> card;
-    void createContent(int width, int height, TestCanvas* renderer) override {
-        SkPaint paint;
-        paint.setColor(0xFF00FFFF);
-        renderer->drawRect(0, 0, width, height, paint);
+    sp<RenderNode> card = new RenderNode();
+    void createContent(int width, int height, TestCanvas* canvas) override {
+        canvas->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); // background
 
-        card = createCard(40, 40, 200, 200);
-        renderer->drawRenderNode(card.get());
+        card->mutateStagingProperties().setLeftTopRightBottom(0, 0, 200, 200);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+        recordNode(*card, [](TestCanvas& canvas) {
+            canvas.saveLayerAlpha(0, 0, 200, 200, 128, SkCanvas::kClipToLayer_SaveFlag);
+            canvas.drawColor(0xFF00FF00, SkXfermode::kSrcOver_Mode); // outer, unclipped
+            canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag);
+            canvas.drawColor(0xFF0000FF, SkXfermode::kSrcOver_Mode); // inner, clipped
+            canvas.restore();
+            canvas.restore();
+        });
+
+        canvas->drawRenderNode(card.get());
     }
     void doFrame(int frameNr) override {
         int curFrame = frameNr % 150;
@@ -410,24 +394,10 @@
         card->mutateStagingProperties().setTranslationY(curFrame);
         card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
     }
-private:
-    sp<RenderNode> createCard(int x, int y, int width, int height) {
-        sp<RenderNode> node = new RenderNode();
-        node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height);
-        node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
-
-        TestCanvas* renderer = startRecording(node.get());
-        SkPaint paint;
-        paint.setColor(0xFFFF00FF);
-        renderer->drawRect(0, 0, width, height, paint);
-
-        endRecording(renderer, node.get());
-        return node;
-    }
 };
-static Benchmark _SimpleRectGrid(BenchmarkInfo{
-    "simplerectgrid",
-    "A simple collection of rects. "
-    "Low CPU/GPU load.",
-    TreeContentAnimation::run<SimpleRectGridAnimation>
+static Benchmark _SaveLayer(BenchmarkInfo{
+    "savelayer",
+    "A nested pair of clipped saveLayer operations. "
+    "Tests the clipped saveLayer codepath. Draws content into offscreen buffers and back again.",
+    TreeContentAnimation::run<SaveLayerAnimation>
 });
diff --git a/libs/hwui/unit_tests/BakedOpStateTests.cpp b/libs/hwui/unit_tests/BakedOpStateTests.cpp
index 82aebea..bc1b69f 100644
--- a/libs/hwui/unit_tests/BakedOpStateTests.cpp
+++ b/libs/hwui/unit_tests/BakedOpStateTests.cpp
@@ -85,13 +85,5 @@
     }
 }
 
-#define UNSUPPORTED_OP(Info, Type) \
-        static void on##Type(Info*, const Type&, const BakedOpState&) { FAIL(); }
-
-class Info {
-public:
-    int index = 0;
-};
-
 }
 }
diff --git a/libs/hwui/unit_tests/FatVectorTests.cpp b/libs/hwui/unit_tests/FatVectorTests.cpp
new file mode 100644
index 0000000..fb760ac5
--- /dev/null
+++ b/libs/hwui/unit_tests/FatVectorTests.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <utils/FatVector.h>
+
+#include <unit_tests/TestUtils.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+template<class VectorType>
+static bool allocationIsInternal(VectorType& v) {
+    // allocation array (from &v[0] to &v[0] + v.capacity) is
+    // located within the vector object itself
+    return (char*)(&v) <= (char*)(&v[0])
+            && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
+}
+
+TEST(FatVector, baseline) {
+    // Verify allocation behavior FatVector contrasts against - allocations are always external
+    std::vector<int> v;
+    for (int i = 0; i < 50; i++) {
+        v.push_back(i);
+        EXPECT_FALSE(allocationIsInternal(v));
+    }
+}
+
+TEST(FatVector, simpleAllocate) {
+    FatVector<int, 4> v;
+    EXPECT_EQ(4u, v.capacity());
+
+    // can insert 4 items into internal buffer
+    for (int i = 0; i < 4; i++) {
+        v.push_back(i);
+        EXPECT_TRUE(allocationIsInternal(v));
+    }
+
+    // then will fall back to external allocation
+    for (int i = 5; i < 50; i++) {
+        v.push_back(i);
+        EXPECT_FALSE(allocationIsInternal(v));
+    }
+}
+
+TEST(FatVector, shrink) {
+    FatVector<int, 10> v;
+    EXPECT_TRUE(allocationIsInternal(v));
+
+    // push into external alloc
+    v.resize(11);
+    EXPECT_FALSE(allocationIsInternal(v));
+
+    // shrinking back to internal alloc succeeds
+    // note that shrinking further will succeed, but is a waste
+    v.resize(10);
+    v.shrink_to_fit();
+    EXPECT_TRUE(allocationIsInternal(v));
+}
+
+TEST(FatVector, destructorInternal) {
+    int count = 0;
+    {
+        // push 1 into external allocation, verify destruction happens once
+        FatVector<TestUtils::SignalingDtor, 0> v;
+        v.emplace_back(&count);
+        EXPECT_FALSE(allocationIsInternal(v));
+        EXPECT_EQ(0, count);
+    }
+    EXPECT_EQ(1, count);
+}
+
+TEST(FatVector, destructorExternal) {
+    int count = 0;
+    {
+        // push 10 into internal allocation, verify 10 destructors called
+        FatVector<TestUtils::SignalingDtor, 10> v;
+        for (int i = 0; i < 10; i++) {
+            v.emplace_back(&count);
+            EXPECT_TRUE(allocationIsInternal(v));
+        }
+        EXPECT_EQ(0, count);
+    }
+    EXPECT_EQ(10, count);
+}
diff --git a/libs/hwui/unit_tests/LinearAllocatorTests.cpp b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
index 02cd77a..0f6b249 100644
--- a/libs/hwui/unit_tests/LinearAllocatorTests.cpp
+++ b/libs/hwui/unit_tests/LinearAllocatorTests.cpp
@@ -17,6 +17,8 @@
 #include <gtest/gtest.h>
 #include <utils/LinearAllocator.h>
 
+#include <unit_tests/TestUtils.h>
+
 using namespace android;
 using namespace android::uirenderer;
 
@@ -25,27 +27,6 @@
     int two = 2;
 };
 
-class SignalingDtor {
-public:
-    SignalingDtor() {
-        mDestroyed = nullptr;
-    }
-    SignalingDtor(bool* destroyedSignal) {
-        mDestroyed = destroyedSignal;
-        *mDestroyed = false;
-    }
-    virtual ~SignalingDtor() {
-        if (mDestroyed) {
-            *mDestroyed = true;
-        }
-    }
-    void setSignal(bool* destroyedSignal) {
-        mDestroyed = destroyedSignal;
-    }
-private:
-    bool* mDestroyed;
-};
-
 TEST(LinearAllocator, alloc) {
     LinearAllocator la;
     EXPECT_EQ(0u, la.usedSize());
@@ -62,31 +43,31 @@
 }
 
 TEST(LinearAllocator, dtor) {
-    bool destroyed[10];
+    int destroyed[10] = { 0 };
     {
         LinearAllocator la;
         for (int i = 0; i < 5; i++) {
-            la.alloc<SignalingDtor>()->setSignal(destroyed + i);
+            la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
             la.alloc<SimplePair>();
         }
         la.alloc(100);
         for (int i = 0; i < 5; i++) {
-            auto sd = new (la) SignalingDtor(destroyed + 5 + i);
+            auto sd = new (la) TestUtils::SignalingDtor(destroyed + 5 + i);
             la.autoDestroy(sd);
             new (la) SimplePair();
         }
         la.alloc(100);
         for (int i = 0; i < 10; i++) {
-            EXPECT_FALSE(destroyed[i]);
+            EXPECT_EQ(0, destroyed[i]);
         }
     }
     for (int i = 0; i < 10; i++) {
-        EXPECT_TRUE(destroyed[i]);
+        EXPECT_EQ(1, destroyed[i]);
     }
 }
 
 TEST(LinearAllocator, rewind) {
-    bool destroyed;
+    int destroyed = 0;
     {
         LinearAllocator la;
         auto addr = la.alloc(100);
@@ -94,17 +75,16 @@
         la.rewindIfLastAlloc(addr, 100);
         EXPECT_GT(16u, la.usedSize());
         size_t emptySize = la.usedSize();
-        auto sigdtor = la.alloc<SignalingDtor>();
+        auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
         sigdtor->setSignal(&destroyed);
-        EXPECT_FALSE(destroyed);
+        EXPECT_EQ(0, destroyed);
         EXPECT_LE(emptySize, la.usedSize());
         la.rewindIfLastAlloc(sigdtor);
-        EXPECT_TRUE(destroyed);
+        EXPECT_EQ(1, destroyed);
         EXPECT_EQ(emptySize, la.usedSize());
-        destroyed = false;
     }
     // Checking for a double-destroy case
-    EXPECT_EQ(destroyed, false);
+    EXPECT_EQ(1, destroyed);
 }
 
 TEST(LinearStdAllocator, simpleAllocate) {
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index d02f89d..ffb575f 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -27,68 +27,67 @@
 namespace android {
 namespace uirenderer {
 
+
 /**
- * Class that redirects static operation dispatch to virtual methods on a Client class.
+ * Virtual class implemented by each test to redirect static operation / state transitions to
+ * virtual methods.
  *
- * The client is recreated for every op (so data cannot be persisted between operations), but the
- * virtual dispatch allows for default behaviors to be specified without enumerating each operation
- * for every test.
+ * Virtual dispatch allows for default behaviors to be specified (very common case in below tests),
+ * and allows Renderer vs Dispatching behavior to be merged.
  *
  * onXXXOp methods fail by default - tests should override ops they expect
+ * startLayer fails by default - tests should override if expected
  * startFrame/endFrame do nothing by default - tests should override to intercept
  */
-template<class CustomClient, class Arg>
-class TestReceiver {
+class TestRendererBase {
 public:
-#define CLIENT_METHOD(Type) \
-    virtual void on##Type(Arg&, const Type&, const BakedOpState&) { FAIL(); }
-    class Client {
-    public:
-        virtual ~Client() {};
-        MAP_OPS(CLIENT_METHOD)
+    virtual ~TestRendererBase() {}
+    virtual OffscreenBuffer* startLayer(uint32_t width, uint32_t height) { ADD_FAILURE(); return nullptr; }
+    virtual void endLayer() { ADD_FAILURE(); }
+    virtual void startFrame(uint32_t width, uint32_t height) {}
+    virtual void endFrame() {}
 
-        virtual void startFrame(Arg& info) {}
-        virtual void endFrame(Arg& info) {}
-    };
+    // define virtual defaults for direct
+#define BASE_OP_METHOD(Type) \
+    virtual void on##Type(const Type&, const BakedOpState&) { ADD_FAILURE(); }
+    MAP_OPS(BASE_OP_METHOD)
+    int getIndex() { return mIndex; }
 
+protected:
+    int mIndex = 0;
+};
+
+/**
+ * Dispatches all static methods to similar formed methods on renderer, which fail by default but
+ * are overriden by subclasses per test.
+ */
+class TestDispatcher {
+public:
 #define DISPATCHER_METHOD(Type) \
-    static void on##Type(Arg& arg, const Type& op, const BakedOpState& state) { \
-        CustomClient client; client.on##Type(arg, op, state); \
+    static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
+        renderer.on##Type(op, state); \
     }
-    MAP_OPS(DISPATCHER_METHOD)
-
-    static void startFrame(Arg& info) {
-        CustomClient client;
-        client.startFrame(info);
-    }
-
-    static void endFrame(Arg& info) {
-        CustomClient client;
-        client.endFrame(info);
-    }
+    MAP_OPS(DISPATCHER_METHOD);
 };
 
-class Info {
-public:
-    int index = 0;
-};
 
-// Receiver class which will fail if it receives any ops
-class FailReceiver : public TestReceiver<FailReceiver, Info>::Client {};
+class FailRenderer : public TestRendererBase {};
 
-class SimpleReceiver : public TestReceiver<SimpleReceiver, Info>::Client {
+class SimpleTestRenderer : public TestRendererBase {
 public:
-    void startFrame(Info& info) override {
-        EXPECT_EQ(0, info.index++);
+    void startFrame(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(0, mIndex++);
+        EXPECT_EQ(100u, width);
+        EXPECT_EQ(200u, height);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(1, info.index++);
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(1, mIndex++);
     }
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(2, info.index++);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(2, mIndex++);
     }
-    void endFrame(Info& info) override {
-        EXPECT_EQ(3, info.index++);
+    void endFrame() override {
+        EXPECT_EQ(3, mIndex++);
     }
 };
 TEST(OpReorderer, simple) {
@@ -97,12 +96,11 @@
         canvas.drawRect(0, 0, 100, 200, SkPaint());
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
-    OpReorderer reorderer;
-    reorderer.defer(200, 200, *dl);
+    OpReorderer reorderer(100, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SimpleReceiver, Info>>(info);
-    EXPECT_EQ(4, info.index); // 2 ops + start + end
+    SimpleTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
 
@@ -113,22 +111,21 @@
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.restore();
     });
-    OpReorderer reorderer;
-    reorderer.defer(200, 200, *dl);
+    OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
+    FailRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 
 static int SIMPLE_BATCHING_LOOPS = 5;
-class SimpleBatchingReceiver : public TestReceiver<SimpleBatchingReceiver, Info>::Client {
+class SimpleBatchingTestRenderer : public TestRendererBase {
 public:
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_TRUE(info.index++ >= SIMPLE_BATCHING_LOOPS);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_TRUE(mIndex++ >= SIMPLE_BATCHING_LOOPS);
     }
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_TRUE(info.index++ < SIMPLE_BATCHING_LOOPS);
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_TRUE(mIndex++ < SIMPLE_BATCHING_LOOPS);
     }
 };
 TEST(OpReorderer, simpleBatching) {
@@ -146,18 +143,17 @@
         canvas.restore();
     });
 
-    OpReorderer reorderer;
-    reorderer.defer(200, 200, *dl);
+    OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SimpleBatchingReceiver, Info>>(info);
-    EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, info.index); // 2 x loops ops, because no merging (TODO: force no merging)
+    SimpleBatchingTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging)
 }
 
-class RenderNodeReceiver : public TestReceiver<RenderNodeReceiver, Info>::Client {
+class RenderNodeTestRenderer : public TestRendererBase {
 public:
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        switch(info.index++) {
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        switch(mIndex++) {
         case 0:
             EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clippedBounds);
             EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
@@ -167,7 +163,7 @@
             EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
             break;
         default:
-            FAIL();
+            ADD_FAILURE();
         }
     }
 };
@@ -196,17 +192,16 @@
     std::vector< sp<RenderNode> > nodes;
     nodes.push_back(parent.get());
 
-    OpReorderer reorderer;
-    reorderer.defer(SkRect::MakeWH(200, 200), 200, 200, nodes);
+    OpReorderer reorderer(SkRect::MakeWH(200, 200), 200, 200, nodes);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<RenderNodeReceiver, Info>>(info);
+    RenderNodeTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
-class ClippedReceiver : public TestReceiver<ClippedReceiver, Info>::Client {
+class ClippedTestRenderer : public TestRendererBase {
 public:
-    void onBitmapOp(Info& info, const BitmapOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(0, info.index++);
+    void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(0, mIndex++);
         EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
         EXPECT_TRUE(state.computedState.transform.isIdentity());
@@ -221,19 +216,27 @@
     std::vector< sp<RenderNode> > nodes;
     nodes.push_back(node.get());
 
-    OpReorderer reorderer;
-    reorderer.defer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
+    OpReorderer reorderer(SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
             200, 200, nodes);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<ClippedReceiver, Info>>(info);
+    ClippedTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 
-class SaveLayerSimpleReceiver : public TestReceiver<SaveLayerSimpleReceiver, Info>::Client {
+class SaveLayerSimpleTestRenderer : public TestRendererBase {
 public:
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(0, info.index++);
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(0, mIndex++);
+        EXPECT_EQ(180u, width);
+        EXPECT_EQ(180u, height);
+        return nullptr;
+    }
+    void endLayer() override {
+        EXPECT_EQ(2, mIndex++);
+    }
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(1, mIndex++);
         EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
         EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(0, 0, 180, 180), state.computedState.clipRect);
@@ -242,8 +245,8 @@
         expectedTransform.loadTranslate(-10, -10, 0);
         EXPECT_MATRIX_APPROX_EQ(expectedTransform, state.computedState.transform);
     }
-    void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
-        EXPECT_EQ(1, info.index++);
+    void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+        EXPECT_EQ(3, mIndex++);
         EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
         EXPECT_EQ(Rect(0, 0, 200, 200), state.computedState.clipRect);
         EXPECT_TRUE(state.computedState.transform.isIdentity());
@@ -256,33 +259,61 @@
         canvas.restore();
     });
 
-    OpReorderer reorderer;
-    reorderer.defer(200, 200, *dl);
+    OpReorderer reorderer(200, 200, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SaveLayerSimpleReceiver, Info>>(info);
-    EXPECT_EQ(2, info.index);
+    SaveLayerSimpleTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(4, renderer.getIndex());
 }
 
 
-// saveLayer1 {rect1, saveLayer2 { rect2 } } will play back as rect2, rect1, layerOp2, layerOp1
-class SaveLayerNestedReceiver : public TestReceiver<SaveLayerNestedReceiver, Info>::Client {
+/* saveLayer1 {rect1, saveLayer2 { rect2 } } will play back as:
+ * - startLayer2, rect2 endLayer2
+ * - startLayer1, rect1, drawLayer2, endLayer1
+ * - startFrame, layerOp1, endFrame
+ */
+class SaveLayerNestedTestRenderer : public TestRendererBase {
 public:
-    void onRectOp(Info& info, const RectOp& op, const BakedOpState& state) override {
-        const int index = info.index++;
+    OffscreenBuffer* startLayer(uint32_t width, uint32_t height) override {
+        const int index = mIndex++;
         if (index == 0) {
-            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
-        } else if (index == 1) {
-            EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
-        } else { FAIL(); }
-    }
-    void onLayerOp(Info& info, const LayerOp& op, const BakedOpState& state) override {
-        const int index = info.index++;
-        if (index == 2) {
-            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+            EXPECT_EQ(400u, width);
+            EXPECT_EQ(400u, height);
+            return (OffscreenBuffer*) 0x400;
         } else if (index == 3) {
+            EXPECT_EQ(800u, width);
+            EXPECT_EQ(800u, height);
+            return (OffscreenBuffer*) 0x800;
+        } else { ADD_FAILURE(); }
+        return (OffscreenBuffer*) nullptr;
+    }
+    void endLayer() override {
+        int index = mIndex++;
+        EXPECT_TRUE(index == 2 || index == 6);
+    }
+    void startFrame(uint32_t width, uint32_t height) override {
+        EXPECT_EQ(7, mIndex++);
+    }
+    void endFrame() override {
+        EXPECT_EQ(9, mIndex++);
+    }
+    void onRectOp(const RectOp& op, const BakedOpState& state) override {
+        const int index = mIndex++;
+        if (index == 1) {
+            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner rect
+        } else if (index == 4) {
+            EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer rect
+        } else { ADD_FAILURE(); }
+    }
+    void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+        const int index = mIndex++;
+        if (index == 5) {
+            EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
+            EXPECT_EQ(Rect(0, 0, 400, 400), op.unmappedBounds); // inner layer
+        } else if (index == 8) {
+            EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
             EXPECT_EQ(Rect(0, 0, 800, 800), op.unmappedBounds); // outer layer
-        } else { FAIL(); }
+        } else { ADD_FAILURE(); }
     }
 };
 TEST(OpReorderer, saveLayerNested) {
@@ -299,12 +330,11 @@
         canvas.restore();
     });
 
-    OpReorderer reorderer;
-    reorderer.defer(800, 800, *dl);
+    OpReorderer reorderer(800, 800, *dl);
 
-    Info info;
-    reorderer.replayBakedOps<TestReceiver<SaveLayerNestedReceiver, Info>>(info);
-    EXPECT_EQ(4, info.index);
+    SaveLayerNestedTestRenderer renderer;
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(10, renderer.getIndex());
 }
 
 TEST(OpReorderer, saveLayerContentRejection) {
@@ -319,12 +349,11 @@
         canvas.restore();
         canvas.restore();
     });
-    OpReorderer reorderer;
-    reorderer.defer(200, 200, *dl);
-    Info info;
+    OpReorderer reorderer(200, 200, *dl);
 
+    FailRenderer renderer;
     // should see no ops, even within the layer, since the layer should be rejected
-    reorderer.replayBakedOps<TestReceiver<FailReceiver, Info>>(info);
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
 
 } // namespace uirenderer
diff --git a/libs/hwui/unit_tests/RecordingCanvasTests.cpp b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
index c023123..e8cdf46 100644
--- a/libs/hwui/unit_tests/RecordingCanvasTests.cpp
+++ b/libs/hwui/unit_tests/RecordingCanvasTests.cpp
@@ -38,7 +38,7 @@
         canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
         canvas.restore();
     });
-    playbackOps(*dl, [](const RecordedOp& op) { FAIL(); });
+    playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
 }
 
 TEST(RecordingCanvas, testSimpleRectRecord) {
@@ -135,7 +135,7 @@
             // TODO: add asserts
             break;
         default:
-            FAIL();
+            ADD_FAILURE();
         }
     });
     EXPECT_EQ(3, count);
diff --git a/libs/hwui/unit_tests/TestUtils.h b/libs/hwui/unit_tests/TestUtils.h
index 99ecc9b..5b09fda 100644
--- a/libs/hwui/unit_tests/TestUtils.h
+++ b/libs/hwui/unit_tests/TestUtils.h
@@ -39,6 +39,24 @@
 
 class TestUtils {
 public:
+    class SignalingDtor {
+    public:
+        SignalingDtor()
+                : mSignal(nullptr) {}
+        SignalingDtor(int* signal)
+                : mSignal(signal) {}
+        void setSignal(int* signal) {
+            mSignal = signal;
+        }
+        ~SignalingDtor() {
+            if (mSignal) {
+                (*mSignal)++;
+            }
+        }
+    private:
+        int* mSignal;
+    };
+
     static bool matricesAreApproxEqual(const Matrix4& a, const Matrix4& b) {
         for (int i = 0; i < 16; i++) {
             if (!MathUtils::areEqual(a[i], b[i])) {
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
new file mode 100644
index 0000000..c3c16c5a
--- /dev/null
+++ b/libs/hwui/utils/FatVector.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2015, The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_FAT_VECTOR_H
+#define ANDROID_FAT_VECTOR_H
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+#include <type_traits>
+#include <utils/Log.h>
+
+#include <vector>
+
+namespace android {
+namespace uirenderer {
+
+template <typename T, size_t SIZE>
+class InlineStdAllocator {
+public:
+    struct Allocation {
+        PREVENT_COPY_AND_ASSIGN(Allocation);
+    public:
+        Allocation() {};
+        // char array instead of T array, so memory is uninitialized, with no destructors run
+        char array[sizeof(T) * SIZE];
+        bool inUse = false;
+    };
+
+    typedef T value_type; // needed to implement std::allocator
+    typedef T* pointer; // needed to implement std::allocator
+
+    InlineStdAllocator(Allocation& allocation)
+            : mAllocation(allocation) {}
+    InlineStdAllocator(const InlineStdAllocator& other)
+            : mAllocation(other.mAllocation) {}
+    ~InlineStdAllocator() {}
+
+    T* allocate(size_t num, const void* = 0) {
+        if (!mAllocation.inUse && num <= SIZE) {
+            mAllocation.inUse = true;
+            return (T*) mAllocation.array;
+        } else {
+            return (T*) malloc(num * sizeof(T));
+        }
+    }
+
+    void deallocate(pointer p, size_t num) {
+        if (p == (T*)mAllocation.array) {
+            mAllocation.inUse = false;
+        } else {
+            // 'free' instead of delete here - destruction handled separately
+            free(p);
+        }
+    }
+    Allocation& mAllocation;
+};
+
+/**
+ * std::vector with SIZE elements preallocated into an internal buffer.
+ *
+ * Useful for avoiding the cost of malloc in cases where only SIZE or
+ * fewer elements are needed in the common case.
+ */
+template <typename T, size_t SIZE>
+class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
+public:
+    FatVector() : std::vector<T, InlineStdAllocator<T, SIZE>>(
+            InlineStdAllocator<T, SIZE>(mAllocation)) {
+        this->reserve(SIZE);
+    }
+private:
+    typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/hwui/utils/NinePatchImpl.cpp b/libs/hwui/utils/NinePatchImpl.cpp
index f51f5df..985f3fb 100644
--- a/libs/hwui/utils/NinePatchImpl.cpp
+++ b/libs/hwui/utils/NinePatchImpl.cpp
@@ -82,7 +82,7 @@
         }
     } else {
     SLOW_CASE:
-        canvas->drawBitmapRect(bitmap, &src, dst, &paint);
+        canvas->drawBitmapRect(bitmap, SkRect::Make(src), dst, &paint);
     }
 }
 
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
new file mode 100644
index 0000000..84aae75
--- /dev/null
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "TestWindowContext.h"
+
+#include "AnimationContext.h"
+#include "DisplayListCanvas.h"
+#include "IContextFactory.h"
+#include "RenderNode.h"
+#include "SkTypes.h"
+#include "gui/BufferQueue.h"
+#include "gui/CpuConsumer.h"
+#include "gui/IGraphicBufferConsumer.h"
+#include "gui/IGraphicBufferProducer.h"
+#include "gui/Surface.h"
+#include "renderthread/RenderProxy.h"
+
+
+namespace {
+
+/**
+ * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
+ */
+class ContextFactory : public android::uirenderer::IContextFactory {
+public:
+    android::uirenderer::AnimationContext* createAnimationContext
+        (android::uirenderer::renderthread::TimeLord& clock) override {
+        return new android::uirenderer::AnimationContext(clock);
+    }
+};
+
+} // anonymous namespace
+
+namespace android {
+namespace uirenderer {
+
+/**
+  Android strong pointers (android::sp) can't hold forward-declared classes,
+  so we have to use pointer-to-implementation here if we want to hide the
+  details from our non-framework users.
+*/
+
+class TestWindowContext::TestWindowData {
+
+public:
+
+    TestWindowData(SkISize size) : mSize(size) {
+        android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+        mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
+        mCpuConsumer->setName(android::String8("TestWindowContext"));
+        mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
+        mAndroidSurface = new android::Surface(mProducer);
+        native_window_set_buffers_dimensions(mAndroidSurface.get(),
+                                             mSize.width(), mSize.height());
+        native_window_set_buffers_format(mAndroidSurface.get(),
+                                         android::PIXEL_FORMAT_RGBA_8888);
+        native_window_set_usage(mAndroidSurface.get(),
+                                GRALLOC_USAGE_SW_READ_OFTEN |
+                                GRALLOC_USAGE_SW_WRITE_NEVER |
+                                GRALLOC_USAGE_HW_RENDER);
+        mRootNode.reset(new android::uirenderer::RenderNode());
+        mRootNode->incStrong(nullptr);
+        mRootNode->mutateStagingProperties().setLeftTopRightBottom
+            (0, 0, mSize.width(), mSize.height());
+        mRootNode->mutateStagingProperties().setClipToBounds(false);
+        mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
+        ContextFactory factory;
+        mProxy.reset
+            (new android::uirenderer::renderthread::RenderProxy(false,
+                                                                mRootNode.get(),
+                                                                &factory));
+        mProxy->loadSystemProperties();
+        mProxy->initialize(mAndroidSurface.get());
+        float lightX = mSize.width() / 2.0f;
+        android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
+        mProxy->setup(mSize.width(), mSize.height(), 800.0f,
+                             255 * 0.075f, 255 * 0.15f);
+        mProxy->setLightCenter(lightVector);
+        mCanvas.reset(new
+            android::uirenderer::DisplayListCanvas(mSize.width(),
+                                                   mSize.height()));
+    }
+
+    SkCanvas* prepareToDraw() {
+        //mCanvas->reset(mSize.width(), mSize.height());
+        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(),
+                               SkRegion::Op::kReplace_Op);
+        return mCanvas->asSkCanvas();
+    }
+
+    void finishDrawing() {
+        mRootNode->setStagingDisplayList(mCanvas->finishRecording());
+        mProxy->syncAndDrawFrame();
+        // Surprisingly, calling mProxy->fence() here appears to make no difference to
+        // the timings we record.
+    }
+
+    void fence() {
+        mProxy->fence();
+    }
+
+    bool capturePixels(SkBitmap* bmp) {
+        SkImageInfo destinationConfig =
+            SkImageInfo::Make(mSize.width(), mSize.height(),
+                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+        bmp->allocPixels(destinationConfig);
+        sk_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
+                    mSize.width() * mSize.height());
+
+        android::CpuConsumer::LockedBuffer nativeBuffer;
+        android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
+        if (retval == android::BAD_VALUE) {
+            SkDebugf("write_canvas_png() got no buffer; returning transparent");
+            // No buffer ready to read - commonly triggered by dm sending us
+            // a no-op source, or calling code that doesn't do anything on this
+            // backend.
+            bmp->eraseColor(SK_ColorTRANSPARENT);
+            return false;
+        } else if (retval) {
+            SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
+            return false;
+        }
+
+        // Move the pixels into the destination SkBitmap
+
+        SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
+                       "Native buffer not RGBA!");
+        SkImageInfo nativeConfig =
+            SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
+                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+
+        // Android stride is in pixels, Skia stride is in bytes
+        SkBitmap nativeWrapper;
+        bool success =
+            nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
+        if (!success) {
+            SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
+            return false;
+        }
+
+        SK_ALWAYSBREAK(bmp->colorType() == kRGBA_8888_SkColorType &&
+                       "Destination buffer not RGBA!");
+        success =
+            nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
+        if (!success) {
+            SkDebugf("Failed to extract pixels from HWUI buffer");
+            return false;
+        }
+
+        mCpuConsumer->unlockBuffer(nativeBuffer);
+
+        return true;
+    }
+
+private:
+
+    std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
+    std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
+    std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
+    android::sp<android::IGraphicBufferProducer> mProducer;
+    android::sp<android::IGraphicBufferConsumer> mConsumer;
+    android::sp<android::CpuConsumer> mCpuConsumer;
+    android::sp<android::Surface> mAndroidSurface;
+    SkISize mSize;
+};
+
+
+TestWindowContext::TestWindowContext() :
+    mData (nullptr) { }
+
+void TestWindowContext::initialize(int width, int height)  {
+    mData = new TestWindowData(SkISize::Make(width, height));
+}
+
+SkCanvas* TestWindowContext::prepareToDraw() {
+    return mData ? mData->prepareToDraw() : nullptr;
+}
+
+void TestWindowContext::finishDrawing() {
+    if (mData) {
+        mData->finishDrawing();
+    }
+}
+
+void TestWindowContext::fence() {
+    if (mData) {
+        mData->fence();
+    }
+}
+
+bool TestWindowContext::capturePixels(SkBitmap* bmp) {
+    return mData ? mData->capturePixels(bmp) : false;
+}
+
+} // namespace uirenderer
+} // namespace android
+
diff --git a/libs/hwui/utils/TestWindowContext.h b/libs/hwui/utils/TestWindowContext.h
new file mode 100644
index 0000000..445a11b
--- /dev/null
+++ b/libs/hwui/utils/TestWindowContext.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef TESTWINDOWCONTEXT_H_
+#define TESTWINDOWCONTEXT_H_
+
+#include <cutils/compiler.h>
+
+class SkBitmap;
+class SkCanvas;
+
+namespace android {
+
+namespace uirenderer {
+
+/**
+  Wraps all libui/libgui classes and types that external tests depend on,
+  exposing only primitive Skia types.
+*/
+
+class ANDROID_API TestWindowContext {
+
+public:
+
+    TestWindowContext();
+
+    /// We need to know the size of the window.
+    void initialize(int width, int height);
+
+    /// Returns a canvas to draw into; NULL if not yet initialize()d.
+    SkCanvas* prepareToDraw();
+
+    /// Flushes all drawing commands to HWUI; no-op if not yet initialize()d.
+    void finishDrawing();
+
+    /// Blocks until HWUI has processed all pending drawing commands;
+    /// no-op if not yet initialize()d.
+    void fence();
+
+    /// Returns false if not yet initialize()d.
+    bool capturePixels(SkBitmap* bmp);
+
+private:
+    /// Hidden implementation.
+    class TestWindowData;
+
+    TestWindowData* mData;
+
+};
+
+}  // namespace uirenderer
+}  // namespace android
+
+#endif  // TESTWINDOWCONTEXT_H_
+
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/libs/hwui/utils/TimeUtils.h
similarity index 60%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to libs/hwui/utils/TimeUtils.h
index 6769716..8d42d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/libs/hwui/utils/TimeUtils.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,14 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#ifndef UTILS_TIMEUTILS_H
+#define UTILS_TIMEUTILS_H
 
-package com.android.systemui.recents.model;
+#include <utils/Timers.h>
 
-/**
- * The String LRU cache.
- */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+namespace android {
+namespace uirenderer {
+
+constexpr nsecs_t operator"" _ms (unsigned long long ms) {
+    return milliseconds_to_nanoseconds(ms);
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* UTILS_TIMEUTILS_H */
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index 4a1d7e7..c9586e4 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -42,15 +42,14 @@
 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds
 static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds
 
-// Time to wait between animation frames.
-static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60;
-
 // Time to spend fading out the spot completely.
 static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms
 
 // Time to spend fading out the pointer completely.
 static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms
 
+// The number of events to be read at once for DisplayEventReceiver.
+static const int EVENT_BUFFER_SIZE = 100;
 
 // --- PointerController ---
 
@@ -59,6 +58,13 @@
         mPolicy(policy), mLooper(looper), mSpriteController(spriteController) {
     mHandler = new WeakMessageHandler(this);
 
+    if (mDisplayEventReceiver.initCheck() == NO_ERROR) {
+        mLooper->addFd(mDisplayEventReceiver.getFd(), Looper::POLL_CALLBACK,
+                       Looper::EVENT_INPUT, this, nullptr);
+    } else {
+        ALOGE("Failed to initialize DisplayEventReceiver.");
+    }
+
     AutoMutex _l(mLock);
 
     mLocked.animationPending = false;
@@ -416,21 +422,49 @@
 
 void PointerController::handleMessage(const Message& message) {
     switch (message.what) {
-    case MSG_ANIMATE:
-        doAnimate();
-        break;
     case MSG_INACTIVITY_TIMEOUT:
         doInactivityTimeout();
         break;
     }
 }
 
-void PointerController::doAnimate() {
+int PointerController::handleEvent(int /* fd */, int events, void* /* data */) {
+    if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
+        ALOGE("Display event receiver pipe was closed or an error occurred.  "
+              "events=0x%x", events);
+        return 0; // remove the callback
+    }
+
+    if (!(events & Looper::EVENT_INPUT)) {
+        ALOGW("Received spurious callback for unhandled poll event.  "
+              "events=0x%x", events);
+        return 1; // keep the callback
+    }
+
+    bool gotVsync = false;
+    ssize_t n;
+    nsecs_t timestamp;
+    DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
+    while ((n = mDisplayEventReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
+        for (size_t i = 0; i < static_cast<size_t>(n); ++i) {
+            if (buf[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
+                timestamp = buf[i].header.timestamp;
+                gotVsync = true;
+            }
+        }
+    }
+    if (gotVsync) {
+        doAnimate(timestamp);
+    }
+    return 1;  // keep the callback
+}
+
+void PointerController::doAnimate(nsecs_t timestamp) {
     AutoMutex _l(mLock);
 
     bool keepAnimating = false;
     mLocked.animationPending = false;
-    nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime;
+    nsecs_t frameDelay = timestamp - mLocked.animationTime;
 
     // Animate pointer fade.
     if (mLocked.pointerFadeDirection < 0) {
@@ -481,7 +515,7 @@
     if (!mLocked.animationPending) {
         mLocked.animationPending = true;
         mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC);
-        mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE));
+        mDisplayEventReceiver.requestNextVsync();
     }
 }
 
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 24a1681..6d840db 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -28,6 +28,7 @@
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
 #include <utils/String8.h>
+#include <gui/DisplayEventReceiver.h>
 
 #include <SkBitmap.h>
 
@@ -68,7 +69,8 @@
  *
  * Handles pointer acceleration and animation.
  */
-class PointerController : public PointerControllerInterface, public MessageHandler {
+class PointerController : public PointerControllerInterface, public MessageHandler,
+                          public LooperCallback {
 protected:
     virtual ~PointerController();
 
@@ -106,7 +108,6 @@
     static const size_t MAX_SPOTS = 12;
 
     enum {
-        MSG_ANIMATE,
         MSG_INACTIVITY_TIMEOUT,
     };
 
@@ -136,6 +137,8 @@
     sp<SpriteController> mSpriteController;
     sp<WeakMessageHandler> mHandler;
 
+    DisplayEventReceiver mDisplayEventReceiver;
+
     PointerResources mResources;
 
     struct Locked {
@@ -173,7 +176,8 @@
     void setPositionLocked(float x, float y);
 
     void handleMessage(const Message& message);
-    void doAnimate();
+    int handleEvent(int fd, int events, void* data);
+    void doAnimate(nsecs_t timestamp);
     void doInactivityTimeout();
 
     void startAnimationLocked();
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index bf3387b..4d0d1bd 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -78,32 +78,51 @@
      */
     public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
 
+    /**
+     * Bit mask for mFieldsMask indicating the presence of mAltitude.
+     */
+    private static final byte HAS_ALTITUDE_MASK = 1;
+    /**
+     * Bit mask for mFieldsMask indicating the presence of mSpeed.
+     */
+    private static final byte HAS_SPEED_MASK = 2;
+    /**
+     * Bit mask for mFieldsMask indicating the presence of mBearing.
+     */
+    private static final byte HAS_BEARING_MASK = 4;
+    /**
+     * Bit mask for mFieldsMask indicating the presence of mAccuracy.
+     */
+    private static final byte HAS_ACCURACY_MASK = 8;
+    /**
+     * Bit mask for mFieldsMask indicating location is from a mock provider.
+     */
+    private static final byte HAS_MOCK_PROVIDER_MASK = 16;
+
+    // Cached data to make bearing/distance computations more efficient for the case
+    // where distanceTo and bearingTo are called in sequence.  Assume this typically happens
+    // on the same thread for caching purposes.
+    private static ThreadLocal<BearingDistanceCache> sBearingDistanceCache
+            = new ThreadLocal<BearingDistanceCache>() {
+        @Override
+        protected BearingDistanceCache initialValue() {
+            return new BearingDistanceCache();
+        }
+    };
+
     private String mProvider;
     private long mTime = 0;
     private long mElapsedRealtimeNanos = 0;
     private double mLatitude = 0.0;
     private double mLongitude = 0.0;
-    private boolean mHasAltitude = false;
     private double mAltitude = 0.0f;
-    private boolean mHasSpeed = false;
     private float mSpeed = 0.0f;
-    private boolean mHasBearing = false;
     private float mBearing = 0.0f;
-    private boolean mHasAccuracy = false;
     private float mAccuracy = 0.0f;
     private Bundle mExtras = null;
-    private boolean mIsFromMockProvider = false;
 
-    // Cache the inputs and outputs of computeDistanceAndBearing
-    // so calls to distanceTo() and bearingTo() can share work
-    private double mLat1 = 0.0;
-    private double mLon1 = 0.0;
-    private double mLat2 = 0.0;
-    private double mLon2 = 0.0;
-    private float mDistance = 0.0f;
-    private float mInitialBearing = 0.0f;
-    // Scratchpad
-    private final float[] mResults = new float[2];
+    // A bitmask of fields present in this object (see HAS_* constants defined above).
+    private byte mFieldsMask = 0;
 
     /**
      * Construct a new Location with a named provider.
@@ -131,18 +150,14 @@
         mProvider = l.mProvider;
         mTime = l.mTime;
         mElapsedRealtimeNanos = l.mElapsedRealtimeNanos;
+        mFieldsMask = l.mFieldsMask;
         mLatitude = l.mLatitude;
         mLongitude = l.mLongitude;
-        mHasAltitude = l.mHasAltitude;
         mAltitude = l.mAltitude;
-        mHasSpeed = l.mHasSpeed;
         mSpeed = l.mSpeed;
-        mHasBearing = l.mHasBearing;
         mBearing = l.mBearing;
-        mHasAccuracy = l.mHasAccuracy;
         mAccuracy = l.mAccuracy;
         mExtras = (l.mExtras == null) ? null : new Bundle(l.mExtras);
-        mIsFromMockProvider = l.mIsFromMockProvider;
     }
 
     /**
@@ -152,18 +167,14 @@
         mProvider = null;
         mTime = 0;
         mElapsedRealtimeNanos = 0;
+        mFieldsMask = 0;
         mLatitude = 0;
         mLongitude = 0;
-        mHasAltitude = false;
         mAltitude = 0;
-        mHasSpeed = false;
         mSpeed = 0;
-        mHasBearing = false;
         mBearing = 0;
-        mHasAccuracy = false;
         mAccuracy = 0;
         mExtras = null;
-        mIsFromMockProvider = false;
     }
 
     /**
@@ -257,11 +268,13 @@
             int deg = Integer.parseInt(degrees);
             double min;
             double sec = 0.0;
+            boolean secPresent = false;
 
             if (st.hasMoreTokens()) {
                 min = Integer.parseInt(minutes);
                 String seconds = st.nextToken();
                 sec = Double.parseDouble(seconds);
+                secPresent = true;
             } else {
                 min = Double.parseDouble(minutes);
             }
@@ -273,11 +286,15 @@
             if ((deg < 0.0) || (deg > 179 && !isNegative180)) {
                 throw new IllegalArgumentException("coordinate=" + coordinate);
             }
-            if (min < 0 || min > 59) {
+
+            // min must be in [0, 59] if seconds are present, otherwise [0.0, 60.0)
+            if (min < 0 || min >= 60 || (secPresent && (min > 59))) {
                 throw new IllegalArgumentException("coordinate=" +
                         coordinate);
             }
-            if (sec < 0 || sec > 59) {
+
+            // sec must be in [0.0, 60.0)
+            if (sec < 0 || sec >= 60) {
                 throw new IllegalArgumentException("coordinate=" +
                         coordinate);
             }
@@ -291,7 +308,7 @@
     }
 
     private static void computeDistanceAndBearing(double lat1, double lon1,
-        double lat2, double lon2, float[] results) {
+        double lat2, double lon2, BearingDistanceCache results) {
         // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
         // using the "Inverse Formula" (section 4)
 
@@ -376,19 +393,19 @@
         }
 
         float distance = (float) (b * A * (sigma - deltaSigma));
-        results[0] = distance;
-        if (results.length > 1) {
-            float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
-                cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
-            initialBearing *= 180.0 / Math.PI;
-            results[1] = initialBearing;
-            if (results.length > 2) {
-                float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
-                    -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
-                finalBearing *= 180.0 / Math.PI;
-                results[2] = finalBearing;
-            }
-        }
+        results.mDistance = distance;
+        float initialBearing = (float) Math.atan2(cosU2 * sinLambda,
+            cosU1 * sinU2 - sinU1 * cosU2 * cosLambda);
+        initialBearing *= 180.0 / Math.PI;
+        results.mInitialBearing = initialBearing;
+        float finalBearing = (float) Math.atan2(cosU1 * sinLambda,
+                -sinU1 * cosU2 + cosU1 * sinU2 * cosLambda);
+        finalBearing *= 180.0 / Math.PI;
+        results.mFinalBearing = finalBearing;
+        results.mLat1 = lat1;
+        results.mLat2 = lat2;
+        results.mLon1 = lon1;
+        results.mLon2 = lon2;
     }
 
     /**
@@ -414,8 +431,16 @@
         if (results == null || results.length < 1) {
             throw new IllegalArgumentException("results is null or has length < 1");
         }
+        BearingDistanceCache cache = sBearingDistanceCache.get();
         computeDistanceAndBearing(startLatitude, startLongitude,
-            endLatitude, endLongitude, results);
+                endLatitude, endLongitude, cache);
+        results[0] = cache.mDistance;
+        if (results.length > 1) {
+            results[1] = cache.mInitialBearing;
+            if (results.length > 2) {
+                results[2] = cache.mFinalBearing;
+            }
+        }
     }
 
     /**
@@ -427,21 +452,14 @@
      * @return the approximate distance in meters
      */
     public float distanceTo(Location dest) {
+        BearingDistanceCache cache = sBearingDistanceCache.get();
         // See if we already have the result
-        synchronized (mResults) {
-            if (mLatitude != mLat1 || mLongitude != mLon1 ||
-                dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
-                computeDistanceAndBearing(mLatitude, mLongitude,
-                    dest.mLatitude, dest.mLongitude, mResults);
-                mLat1 = mLatitude;
-                mLon1 = mLongitude;
-                mLat2 = dest.mLatitude;
-                mLon2 = dest.mLongitude;
-                mDistance = mResults[0];
-                mInitialBearing = mResults[1];
-            }
-            return mDistance;
+        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
+            dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
+            computeDistanceAndBearing(mLatitude, mLongitude,
+                dest.mLatitude, dest.mLongitude, cache);
         }
+        return cache.mDistance;
     }
 
     /**
@@ -455,21 +473,14 @@
      * @return the initial bearing in degrees
      */
     public float bearingTo(Location dest) {
-        synchronized (mResults) {
-            // See if we already have the result
-            if (mLatitude != mLat1 || mLongitude != mLon1 ||
-                            dest.mLatitude != mLat2 || dest.mLongitude != mLon2) {
-                computeDistanceAndBearing(mLatitude, mLongitude,
-                    dest.mLatitude, dest.mLongitude, mResults);
-                mLat1 = mLatitude;
-                mLon1 = mLongitude;
-                mLat2 = dest.mLatitude;
-                mLon2 = dest.mLongitude;
-                mDistance = mResults[0];
-                mInitialBearing = mResults[1];
-            }
-            return mInitialBearing;
+        BearingDistanceCache cache = sBearingDistanceCache.get();
+        // See if we already have the result
+        if (mLatitude != cache.mLat1 || mLongitude != cache.mLon1 ||
+                        dest.mLatitude != cache.mLat2 || dest.mLongitude != cache.mLon2) {
+            computeDistanceAndBearing(mLatitude, mLongitude,
+                dest.mLatitude, dest.mLongitude, cache);
         }
+        return cache.mInitialBearing;
     }
 
     /**
@@ -585,7 +596,7 @@
      * True if this location has an altitude.
      */
     public boolean hasAltitude() {
-        return mHasAltitude;
+        return (mFieldsMask & HAS_ALTITUDE_MASK) != 0;
     }
 
     /**
@@ -605,7 +616,7 @@
      */
     public void setAltitude(double altitude) {
         mAltitude = altitude;
-        mHasAltitude = true;
+        mFieldsMask |= HAS_ALTITUDE_MASK;
     }
 
     /**
@@ -616,14 +627,14 @@
      */
     public void removeAltitude() {
         mAltitude = 0.0f;
-        mHasAltitude = false;
+        mFieldsMask &= ~HAS_ALTITUDE_MASK;
     }
 
     /**
      * True if this location has a speed.
      */
     public boolean hasSpeed() {
-        return mHasSpeed;
+        return (mFieldsMask & HAS_SPEED_MASK) != 0;
     }
 
     /**
@@ -642,7 +653,7 @@
      */
     public void setSpeed(float speed) {
         mSpeed = speed;
-        mHasSpeed = true;
+        mFieldsMask |= HAS_SPEED_MASK;
     }
 
     /**
@@ -653,14 +664,14 @@
      */
     public void removeSpeed() {
         mSpeed = 0.0f;
-        mHasSpeed = false;
+        mFieldsMask &= ~HAS_SPEED_MASK;
     }
 
     /**
      * True if this location has a bearing.
      */
     public boolean hasBearing() {
-        return mHasBearing;
+        return (mFieldsMask & HAS_BEARING_MASK) != 0;
     }
 
     /**
@@ -692,7 +703,7 @@
             bearing -= 360.0f;
         }
         mBearing = bearing;
-        mHasBearing = true;
+        mFieldsMask |= HAS_BEARING_MASK;
     }
 
     /**
@@ -703,7 +714,7 @@
      */
     public void removeBearing() {
         mBearing = 0.0f;
-        mHasBearing = false;
+        mFieldsMask &= ~HAS_BEARING_MASK;
     }
 
     /**
@@ -713,7 +724,7 @@
      * accuracy.
      */
     public boolean hasAccuracy() {
-        return mHasAccuracy;
+        return (mFieldsMask & HAS_ACCURACY_MASK) != 0;
     }
 
     /**
@@ -751,7 +762,7 @@
      */
     public void setAccuracy(float accuracy) {
         mAccuracy = accuracy;
-        mHasAccuracy = true;
+        mFieldsMask |= HAS_ACCURACY_MASK;
     }
 
     /**
@@ -762,7 +773,7 @@
      */
     public void removeAccuracy() {
         mAccuracy = 0.0f;
-        mHasAccuracy = false;
+        mFieldsMask &= ~HAS_ACCURACY_MASK;
     }
 
     /**
@@ -780,7 +791,7 @@
     @SystemApi
     public boolean isComplete() {
         if (mProvider == null) return false;
-        if (!mHasAccuracy) return false;
+        if (!hasAccuracy()) return false;
         if (mTime == 0) return false;
         if (mElapsedRealtimeNanos == 0) return false;
         return true;
@@ -798,8 +809,8 @@
     @SystemApi
     public void makeComplete() {
         if (mProvider == null) mProvider = "?";
-        if (!mHasAccuracy) {
-            mHasAccuracy = true;
+        if (!hasAccuracy()) {
+            mFieldsMask |= HAS_ACCURACY_MASK;
             mAccuracy = 100.0f;
         }
         if (mTime == 0) mTime = System.currentTimeMillis();
@@ -838,7 +849,7 @@
         s.append("Location[");
         s.append(mProvider);
         s.append(String.format(" %.6f,%.6f", mLatitude, mLongitude));
-        if (mHasAccuracy) s.append(String.format(" acc=%.0f", mAccuracy));
+        if (hasAccuracy()) s.append(String.format(" acc=%.0f", mAccuracy));
         else s.append(" acc=???");
         if (mTime == 0) {
             s.append(" t=?!?");
@@ -849,10 +860,10 @@
             s.append(" et=");
             TimeUtils.formatDuration(mElapsedRealtimeNanos / 1000000L, s);
         }
-        if (mHasAltitude) s.append(" alt=").append(mAltitude);
-        if (mHasSpeed) s.append(" vel=").append(mSpeed);
-        if (mHasBearing) s.append(" bear=").append(mBearing);
-        if (mIsFromMockProvider) s.append(" mock");
+        if (hasAltitude()) s.append(" alt=").append(mAltitude);
+        if (hasSpeed()) s.append(" vel=").append(mSpeed);
+        if (hasBearing()) s.append(" bear=").append(mBearing);
+        if (isFromMockProvider()) s.append(" mock");
 
         if (mExtras != null) {
             s.append(" {").append(mExtras).append('}');
@@ -873,18 +884,14 @@
             Location l = new Location(provider);
             l.mTime = in.readLong();
             l.mElapsedRealtimeNanos = in.readLong();
+            l.mFieldsMask = in.readByte();
             l.mLatitude = in.readDouble();
             l.mLongitude = in.readDouble();
-            l.mHasAltitude = in.readInt() != 0;
             l.mAltitude = in.readDouble();
-            l.mHasSpeed = in.readInt() != 0;
             l.mSpeed = in.readFloat();
-            l.mHasBearing = in.readInt() != 0;
             l.mBearing = in.readFloat();
-            l.mHasAccuracy = in.readInt() != 0;
             l.mAccuracy = in.readFloat();
             l.mExtras = in.readBundle();
-            l.mIsFromMockProvider = in.readInt() != 0;
             return l;
         }
 
@@ -904,18 +911,14 @@
         parcel.writeString(mProvider);
         parcel.writeLong(mTime);
         parcel.writeLong(mElapsedRealtimeNanos);
+        parcel.writeByte(mFieldsMask);
         parcel.writeDouble(mLatitude);
         parcel.writeDouble(mLongitude);
-        parcel.writeInt(mHasAltitude ? 1 : 0);
         parcel.writeDouble(mAltitude);
-        parcel.writeInt(mHasSpeed ? 1 : 0);
         parcel.writeFloat(mSpeed);
-        parcel.writeInt(mHasBearing ? 1 : 0);
         parcel.writeFloat(mBearing);
-        parcel.writeInt(mHasAccuracy ? 1 : 0);
         parcel.writeFloat(mAccuracy);
         parcel.writeBundle(mExtras);
-        parcel.writeInt(mIsFromMockProvider? 1 : 0);
     }
 
     /**
@@ -940,7 +943,7 @@
      * Attaches an extra {@link Location} to this Location.
      *
      * @param key the key associated with the Location extra
-     * @param location the Location to attach
+     * @param value the Location to attach
      * @hide
      */
     public void setExtraLocation(String key, Location value) {
@@ -956,7 +959,7 @@
      * @return true if this Location came from a mock provider, false otherwise
      */
     public boolean isFromMockProvider() {
-        return mIsFromMockProvider;
+        return (mFieldsMask & HAS_MOCK_PROVIDER_MASK) != 0;
     }
 
     /**
@@ -967,6 +970,24 @@
      */
     @SystemApi
     public void setIsFromMockProvider(boolean isFromMockProvider) {
-        mIsFromMockProvider = isFromMockProvider;
+        if (isFromMockProvider) {
+            mFieldsMask |= HAS_MOCK_PROVIDER_MASK;
+        } else {
+            mFieldsMask &= ~HAS_MOCK_PROVIDER_MASK;
+        }
+    }
+
+    /**
+     * Caches data used to compute distance and bearing (so successive calls to {@link #distanceTo}
+     * and {@link #bearingTo} don't duplicate work.
+     */
+    private static class BearingDistanceCache {
+        private double mLat1 = 0.0;
+        private double mLon1 = 0.0;
+        private double mLat2 = 0.0;
+        private double mLon2 = 0.0;
+        private float mDistance = 0.0f;
+        private float mInitialBearing = 0.0f;
+        private float mFinalBearing = 0.0f;
     }
 }
diff --git a/location/tests/locationtests/src/android/location/LocationTest.java b/location/tests/locationtests/src/android/location/LocationTest.java
index 847ac7a..dc8d0f7 100644
--- a/location/tests/locationtests/src/android/location/LocationTest.java
+++ b/location/tests/locationtests/src/android/location/LocationTest.java
@@ -16,6 +16,7 @@
 
 package android.location;
 
+import android.os.Parcel;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import junit.framework.TestCase;
@@ -225,6 +226,40 @@
         assertEquals(message, loc.getBearing(), 0, 0);
     }
 
+    public void testParcel() {
+        final double expectedLat = 33;
+        final double expectedLon = -122;
+        final float expectedAccuracy = 15;
+        final float expectedSpeed = 5;
+        Location loc = new Location("test");
+        loc.setLatitude(expectedLat);
+        loc.setLongitude(expectedLon);
+        loc.setAccuracy(expectedAccuracy);
+        loc.setSpeed(expectedSpeed);
+
+        // Serialize location object into bytes via parcelable capability
+        Parcel parcel = Parcel.obtain();
+        loc.writeToParcel(parcel, 0);
+        byte[] rawBytes = parcel.marshall();
+        parcel.recycle();
+
+        // Turn the bytes back into a location object
+        parcel = Parcel.obtain();
+        parcel.unmarshall(rawBytes, 0, rawBytes.length);
+        parcel.setDataPosition(0);
+        Location deserialized = Location.CREATOR.createFromParcel(parcel);
+        parcel.recycle();
+
+        assertEquals(expectedLat, deserialized.getLatitude());
+        assertEquals(expectedLon, deserialized.getLongitude());
+        assertEquals(expectedAccuracy, deserialized.getAccuracy());
+        assertTrue(deserialized.hasAccuracy());
+        assertEquals(expectedSpeed, deserialized.getSpeed());
+        assertTrue(deserialized.hasSpeed());
+        assertFalse(deserialized.hasBearing());
+        assertFalse(deserialized.hasAltitude());
+        assertFalse(deserialized.isFromMockProvider());
+    }
 }
 
 
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index ba867e1..e0a8026 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -249,7 +249,7 @@
      */
     public @NonNull String getRoot() {
         if (!isConnected()) {
-            throw new IllegalStateException("getSessionToken() called while not connected (state="
+            throw new IllegalStateException("getRoot() called while not connected (state="
                     + getStateLabel(mState) + ")");
         }
         return mRootId;
@@ -776,68 +776,88 @@
      */
     private class MediaServiceConnection implements ServiceConnection {
         @Override
-        public void onServiceConnected(ComponentName name, IBinder binder) {
-            if (DBG) {
-                Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
-                        + " binder=" + binder);
-                dump();
-            }
+        public void onServiceConnected(final ComponentName name, final IBinder binder) {
+            postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (DBG) {
+                        Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
+                                + " binder=" + binder);
+                        dump();
+                    }
 
-            // Make sure we are still the current connection, and that they haven't called
-            // disconnect().
-            if (!isCurrent("onServiceConnected")) {
-                return;
-            }
+                    // Make sure we are still the current connection, and that they haven't called
+                    // disconnect().
+                    if (!isCurrent("onServiceConnected")) {
+                        return;
+                    }
 
-            // Save their binder
-            mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
+                    // Save their binder
+                    mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
 
-            // We make a new mServiceCallbacks each time we connect so that we can drop
-            // responses from previous connections.
-            mServiceCallbacks = getNewServiceCallbacks();
-            mState = CONNECT_STATE_CONNECTING;
+                    // We make a new mServiceCallbacks each time we connect so that we can drop
+                    // responses from previous connections.
+                    mServiceCallbacks = getNewServiceCallbacks();
+                    mState = CONNECT_STATE_CONNECTING;
 
-            // Call connect, which is async. When we get a response from that we will
-            // say that we're connected.
-            try {
-                if (DBG) {
-                    Log.d(TAG, "ServiceCallbacks.onConnect...");
-                    dump();
+                    // Call connect, which is async. When we get a response from that we will
+                    // say that we're connected.
+                    try {
+                        if (DBG) {
+                            Log.d(TAG, "ServiceCallbacks.onConnect...");
+                            dump();
+                        }
+                        mServiceBinder.connect(mContext.getPackageName(), mRootHints,
+                                mServiceCallbacks);
+                    } catch (RemoteException ex) {
+                        // Connect failed, which isn't good. But the auto-reconnect on the service
+                        // will take over and we will come back.  We will also get the
+                        // onServiceDisconnected, which has all the cleanup code.  So let that do
+                        // it.
+                        Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
+                        if (DBG) {
+                            Log.d(TAG, "ServiceCallbacks.onConnect...");
+                            dump();
+                        }
+                    }
                 }
-                mServiceBinder.connect(mContext.getPackageName(), mRootHints, mServiceCallbacks);
-            } catch (RemoteException ex) {
-                // Connect failed, which isn't good. But the auto-reconnect on the service
-                // will take over and we will come back.  We will also get the
-                // onServiceDisconnected, which has all the cleanup code.  So let that do it.
-                Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
-                if (DBG) {
-                    Log.d(TAG, "ServiceCallbacks.onConnect...");
-                    dump();
-                }
-            }
+            });
         }
 
         @Override
-        public void onServiceDisconnected(ComponentName name) {
-            if (DBG) {
-                Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
-                        + " this=" + this + " mServiceConnection=" + mServiceConnection);
-                dump();
+        public void onServiceDisconnected(final ComponentName name) {
+            postOrRun(new Runnable() {
+                @Override
+                public void run() {
+                    if (DBG) {
+                        Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
+                                + " this=" + this + " mServiceConnection=" + mServiceConnection);
+                        dump();
+                    }
+
+                    // Make sure we are still the current connection, and that they haven't called
+                    // disconnect().
+                    if (!isCurrent("onServiceDisconnected")) {
+                        return;
+                    }
+
+                    // Clear out what we set in onServiceConnected
+                    mServiceBinder = null;
+                    mServiceCallbacks = null;
+
+                    // And tell the app that it's suspended.
+                    mState = CONNECT_STATE_SUSPENDED;
+                    mCallback.onConnectionSuspended();
+                }
+            });
+        }
+
+        private void postOrRun(Runnable r) {
+            if (Thread.currentThread() == mHandler.getLooper().getThread()) {
+                r.run();
+            } else {
+                mHandler.post(r);
             }
-
-            // Make sure we are still the current connection, and that they haven't called
-            // disconnect().
-            if (!isCurrent("onServiceDisconnected")) {
-                return;
-            }
-
-            // Clear out what we set in onServiceConnected
-            mServiceBinder = null;
-            mServiceCallbacks = null;
-
-            // And tell the app that it's suspended.
-            mState = CONNECT_STATE_SUSPENDED;
-            mCallback.onConnectionSuspended();
         }
 
         /**
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 45fb579..93dbf3f 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -180,7 +180,8 @@
             Log.e(TAG, "could not open device " + info);
         } else {
             ...
-        }, new Handler(Looper.getMainLooper())
+        }
+    }, new Handler(Looper.getMainLooper())
     );
 </pre>
 
diff --git a/opengl/java/android/opengl/GLES31.java b/opengl/java/android/opengl/GLES31.java
index 3cbaa60..805930e 100644
--- a/opengl/java/android/opengl/GLES31.java
+++ b/opengl/java/android/opengl/GLES31.java
@@ -24,9 +24,14 @@
 
     public static final int GL_VERTEX_SHADER_BIT                            = 0x00000001;
     public static final int GL_FRAGMENT_SHADER_BIT                          = 0x00000002;
+    public static final int GL_COMPUTE_SHADER_BIT                           = 0x00000020;
+    public static final int GL_ALL_SHADER_BITS                              = -1; // 0xFFFFFFFF
+
+    public static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT              = 0x00000001;
+    public static final int GL_ELEMENT_ARRAY_BARRIER_BIT                    = 0x00000002;
     public static final int GL_UNIFORM_BARRIER_BIT                          = 0x00000004;
     public static final int GL_TEXTURE_FETCH_BARRIER_BIT                    = 0x00000008;
-    public static final int GL_COMPUTE_SHADER_BIT                           = 0x00000020;
+    public static final int GL_SHADER_IMAGE_ACCESS_BARRIER_BIT              = 0x00000020;
     public static final int GL_COMMAND_BARRIER_BIT                          = 0x00000040;
     public static final int GL_PIXEL_BUFFER_BARRIER_BIT                     = 0x00000080;
     public static final int GL_TEXTURE_UPDATE_BARRIER_BIT                   = 0x00000100;
@@ -35,7 +40,8 @@
     public static final int GL_TRANSFORM_FEEDBACK_BARRIER_BIT               = 0x00000800;
     public static final int GL_ATOMIC_COUNTER_BARRIER_BIT                   = 0x00001000;
     public static final int GL_SHADER_STORAGE_BARRIER_BIT                   = 0x00002000;
-    public static final int GL_ALL_SHADER_BITS                              = -1; // 0xFFFFFFFF
+    public static final int GL_ALL_BARRIER_BITS                             = -1; // 0xFFFFFFFF
+
 
     public static final int GL_TEXTURE_WIDTH                                = 0x1000;
     public static final int GL_TEXTURE_HEIGHT                               = 0x1001;
diff --git a/packages/BackupRestoreConfirmation/res/values-ne-rNP/strings.xml b/packages/BackupRestoreConfirmation/res/values-ne-rNP/strings.xml
index 473802e..66d340c 100644
--- a/packages/BackupRestoreConfirmation/res/values-ne-rNP/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ne-rNP/strings.xml
@@ -21,14 +21,14 @@
     <string name="backup_confirm_text" msgid="1878021282758896593">"एउटा जोडिएको डेस्कटप कम्प्युटरमा सबै डेटाको एउटा पूर्ण जगेडाको अनुरोध गरिएको छ। के तपाईँ यो हुन दिन चाहनुहुन्छ? \n\nयदि तपाईँले जगेडाको लागि आफैँ अनुरोध गर्नु भएन भने प्रक्रियालाई अगाडि बढ्न अनुमति नदिनुहोस्।"</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"मेरो डेटा ब्याकअप गर्नुहोस्"</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"जगेडा नगर्नुहोस्"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"एउटा जडित डेस्कटप कम्प्युटरबाट सबै डेटाको पूर्ण पुनःबहाली अनुरोध गरियो। के तपाईं यो हुन अनुमति दिनुहुन्छ?\n\nयदि तपाईं आफैं पुनःबहाली अनुरोध गर्नुहुन्न भने अपरेसनलाई अघि बढाउन अनुमति नदिनुहोस्। यसले उपकरणमा भएको कुनै पनि डेटालाई बदल्ने छ!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"एउटा जडित डेस्कटप कम्प्युटरबाट सबै डेटाको पूर्ण पुनःबहाली अनुरोध गरियो। के तपाईँ यो हुन अनुमति दिनुहुन्छ?\n\nयदि तपाईँ आफैं पुनःबहाली अनुरोध गर्नुहुन्न भने अपरेसनलाई अघि बढाउन अनुमति नदिनुहोस्। यसले उपकरणमा भएको कुनै पनि डेटालाई बदल्ने छ!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"मेरो डेटा पुनःबहाली गर्नुहोस्"</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"पुन:स्थापना नगर्नुहोस्"</string>
     <string name="current_password_text" msgid="8268189555578298067">"कृपया तल तपाईंको हालको ब्याकअप पासवर्ड प्रविष्टि गर्नुहोस्:"</string>
     <string name="device_encryption_restore_text" msgid="1570864916855208992">"कृपया तल तपाईंको उपकरण एन्क्रिप्सन पासवर्ड प्रविष्टि गर्नुहोस्:"</string>
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"कृपया तल तपाईंको उपकरण एन्क्रिप्सन पासवर्ड प्रविष्टि गर्नुहोस्: यो ब्याकप सँग्रह एन्क्रिप्ट गर्न पनि प्रयोग हुने छ।"</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"ब्याकप डेटालाई encrypt गर्न पासवर्ड प्रविष्टि गर्नुहोस्, यदि यो खालि छोडिएको खण्डमा तपाईको पुरानै पासवर्ड प्रयोग हुने छ।"</string>
-    <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि तपाईं पूर्ण ब्याकअप डेटा इन्क्रिप्ट गर्न चाहनु हुन्छ भने तल पासवर्ड प्रविष्टि गर्नुहोस्।"</string>
+    <string name="backup_enc_password_optional" msgid="1350137345907579306">"यदि तपाईँ पूर्ण ब्याकअप डेटा इन्क्रिप्ट गर्न चाहनु हुन्छ भने तल पासवर्ड प्रविष्टि गर्नुहोस्।"</string>
     <string name="backup_enc_password_required" msgid="7889652203371654149">"तपाईँको उपकरण गुप्तिकरण गरिए देखि, तपाईंले आफ्नो जगेडा गुप्तिकरण गर्न आवश्यक छ। कृपया तल पासवर्ड प्रविष्ट गर्नुहोस्:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"यदि पुनःबहाली डेटा इन्क्रिप्ट छ भने कृपया तल पासवर्ड प्रविष्टि गर्नुहोस्:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"जगेडा राख्न सुरु हुँदै..."</string>
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index f9e8027..d45345e 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -40,7 +40,7 @@
 
         <activity
             android:name=".ManageRootActivity"
-            android:theme="@style/DocumentsNonDialogTheme"
+            android:theme="@style/DocumentsFullScreenTheme"
             android:icon="@drawable/ic_doc_text">
             <intent-filter>
                 <action android:name="android.provider.action.MANAGE_ROOT" />
@@ -63,7 +63,7 @@
 
         <activity
             android:name=".FilesActivity"
-            android:theme="@style/FilesTheme"
+            android:theme="@style/DocumentsFullScreenTheme"
             android:icon="@drawable/ic_files_app"
             android:label="@string/files_label"
             android:documentLaunchMode="intoExisting">
diff --git a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
index ab414a9..bf19d4e 100644
--- a/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
+++ b/packages/DocumentsUI/res/color/item_doc_grid_overlay.xml
@@ -16,10 +16,6 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item
-        android:state_focused="true"
-        android:color="@color/platform_blue_a200"
-        android:alpha="0.1" />
-    <item
         android:state_activated="true"
         android:color="?android:attr/colorAccent"
         android:alpha="0.1" />
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 085df35..eba00a6 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<com.android.documentsui.DocListItem xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.ListItem xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:background="@drawable/item_doc_list_background"
@@ -137,4 +137,4 @@
 
     </LinearLayout>
 
-</com.android.documentsui.DocListItem>
+</com.android.documentsui.ListItem>
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index d415a84..a8dcbb0 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Dialog">
+    <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.Dialog">
         <!-- We do not specify width of window here because the max size of
              floating window specified by windowFixedWidthis is limited. -->
         <item name="*android:windowFixedHeightMajor">80%</item>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index cb6957d..a376418 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -15,23 +15,15 @@
 -->
 
 <resources>
-    <color name="material_grey_50">#fffafafa</color>
-    <color name="material_grey_300">#ffeeeeee</color>
-    <color name="material_grey_600">#ff757575</color>
-    <color name="material_grey_800">#ff424242</color>
+    <color name="material_grey_400">#ffbdbdbd</color>
 
-    <color name="primary_dark">@*android:color/material_blue_grey_900</color>
-    <color name="primary">@*android:color/material_blue_grey_800</color>
-    <color name="accent">@*android:color/material_deep_teal_500</color>
-
-    <color name="platform_blue_100">#ffd0d9ff</color>
-    <color name="platform_blue_500">#ff5677fc</color>
-    <color name="platform_blue_700">#ff455ede</color>
-    <color name="platform_blue_a100">#ffa6baff</color>
-    <color name="platform_blue_a200">#ffff5177</color>
+    <color name="primary_dark">@*android:color/primary_dark_material_dark</color>
+    <color name="primary">@*android:color/material_blue_grey_900</color>
+    <color name="accent">@*android:color/accent_material_light</color>
+    <color name="action_mode">@color/material_grey_400</color>
     
-    <color name="directory_background">@color/material_grey_300</color>
-    <color name="item_doc_grid_background">#FFFFFFFF</color>
+    <color name="directory_background">@*android:color/material_grey_300</color>
+    <color name="item_doc_grid_background">@android:color/white</color>
     <color name="item_doc_grid_protect_background">#88000000</color>
     <color name="band_select_background">#88ffffff</color>
     <color name="band_select_border">#44000000</color>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index 73538278..ad419aa 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -16,6 +16,6 @@
 
 <resources>
     <bool name="productivity_device">true</bool>
-    <!-- intentionally unset. Vendors should set this in an overlay. -->
+    <!-- Intentionally unset. Vendors should set this in an overlay. -->
     <string name="trusted_quick_viewer_package"></string>
 </resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index c13f144..15d17cc 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -28,7 +28,7 @@
         <item name="android:colorPrimaryDark">@color/primary_dark</item>
         <item name="android:colorPrimary">@color/primary</item>
         <item name="android:colorAccent">@color/accent</item>
-        <item name="colorActionMode">@color/material_grey_800</item>
+        <item name="colorActionMode">@color/action_mode</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -37,14 +37,17 @@
         <item name="android:windowNoTitle">true</item>
 
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
-        <item name="android:alertDialogTheme">@android:style/Theme.Material.Light.Dialog.Alert</item>
     </style>
 
-    <style name="DocumentsBaseTheme.FullScreen" parent="@style/Theme.AppCompat.Light.DarkActionBar">
+    <style name="DocumentsFullScreenTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
         <item name="actionBarWidgetTheme">@null</item>
         <item name="actionBarTheme">@style/ActionBarTheme</item>
         <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
-        <item name="colorActionMode">@color/material_grey_800</item>
+
+        <item name="android:colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:colorPrimary">@color/primary</item>
+        <item name="android:colorAccent">@color/accent</item>
+        <item name="colorActionMode">@color/action_mode</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -55,38 +58,6 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
 
-    <style name="DocumentsNonDialogTheme" parent="@style/DocumentsBaseTheme.FullScreen">
-        <item name="android:colorPrimaryDark">@color/primary_dark</item>
-        <item name="android:colorPrimary">@color/primary</item>
-        <item name="android:colorAccent">@color/accent</item>
-
-        <item name="android:actionModeStyle">@style/ActionModeStyle</item>
-
-        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
-    </style>
-
-    <style name="ActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
-        <item name="android:background">@color/material_grey_600</item>
-    </style>
-
-    <style name="AlertDialogTheme" parent="@android:style/Theme.Material.Light.Dialog.Alert">
-        <item name="android:colorAccent">@color/platform_blue_700</item>
-    </style>
-
-    <style name="FilesTheme" parent="@style/DocumentsBaseTheme.FullScreen">
-        <item name="android:colorPrimaryDark">@color/platform_blue_700</item>
-        <item name="android:colorPrimary">@color/platform_blue_500</item>
-        <item name="android:colorAccent">@color/platform_blue_700</item>
-        <item name="colorControlActivated">@color/platform_blue_a100</item>
-        <item name="android:actionModeStyle">@style/FilesActionModeStyle</item>
-        <item name="colorActionMode">@color/platform_blue_700</item>
-        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
-    </style>
-
-    <style name="FilesActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
-        <item name="android:background">@color/platform_blue_100</item>
-    </style>
-
     <style name="TrimmedHorizontalProgressBar" parent="android:Widget.Material.ProgressBar.Horizontal">
         <item name="android:indeterminateDrawable">@drawable/progress_indeterminate_horizontal_material_trimmed</item>
         <item name="android:minHeight">3dp</item>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 45a8907..a09a22a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -17,7 +17,6 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.State.ACTION_BROWSE;
 import static com.android.documentsui.State.ACTION_CREATE;
 import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.State.MODE_GRID;
@@ -55,7 +54,6 @@
 import android.os.Looper;
 import android.os.OperationCanceledException;
 import android.os.Parcelable;
-import android.os.SystemProperties;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
@@ -95,6 +93,7 @@
 import com.android.documentsui.MultiSelectManager.Selection;
 import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.RecentsProvider.StateColumns;
+import com.android.documentsui.dirlist.FragmentTuner;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
@@ -341,7 +340,7 @@
         mType = getArguments().getInt(EXTRA_TYPE);
         mStateKey = buildStateKey(root, doc);
 
-        mFragmentTuner = pickFragmentTuner(state);
+        mFragmentTuner = FragmentTuner.pick(state);
         mClipper = new DocumentClipper(context);
 
         if (mType == TYPE_RECENT_OPEN) {
@@ -429,7 +428,6 @@
         // Kick off loader at least once
         getLoaderManager().restartLoader(LOADER_ID, null, mCallbacks);
 
-        mFragmentTuner.afterActivityCreated(this);
         updateDisplayState();
     }
 
@@ -1638,21 +1636,6 @@
         }
     }
 
-    private FragmentTuner pickFragmentTuner(final State state) {
-        return state.action == ACTION_BROWSE
-                ? new FilesTuner()
-                : new DefaultTuner(state.action);
-    }
-
-    /**
-     * Interface for specializing the Fragment for the "host" Activity.
-     * Feel free to expand the role of this class to handle other specializations.
-     */
-    private interface FragmentTuner {
-        void updateActionMenu(Menu menu, int dirType, boolean canDelete);
-        void afterActivityCreated(DirectoryFragment fragment);
-    }
-
     /**
      * Abstract task providing support for loading documents *off*
      * the main thread. And if it isn't obvious, creating a list
@@ -1673,65 +1656,6 @@
         abstract void onDocumentsReady(List<DocumentInfo> docs);
     }
 
-    /**
-     * Provides support for Platform specific specializations of DirectoryFragment.
-     */
-    private static final class DefaultTuner implements FragmentTuner {
-
-        private final boolean mManaging;
-
-        public DefaultTuner(int action) {
-            mManaging = (action == ACTION_MANAGE);
-        }
-
-        @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
-            boolean copyEnabled = mManaging && dirType != TYPE_RECENT_OPEN;
-            // TODO: The selection needs to be deletable.
-            boolean moveEnabled =
-                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
-            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
-
-            final MenuItem open = menu.findItem(R.id.menu_open);
-            final MenuItem share = menu.findItem(R.id.menu_share);
-            final MenuItem delete = menu.findItem(R.id.menu_delete);
-            final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
-            final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
-
-            open.setVisible(!mManaging);
-            share.setVisible(mManaging);
-            delete.setVisible(mManaging && canDelete);
-            copyTo.setVisible(copyEnabled);
-            copyTo.setEnabled(copyEnabled);
-            moveTo.setVisible(moveEnabled);
-            moveTo.setEnabled(moveEnabled);
-        }
-
-        @Override
-        public void afterActivityCreated(DirectoryFragment fragment) {}
-    }
-
-    /**
-     * Provides support for Files activity specific specializations of DirectoryFragment.
-     */
-    private static final class FilesTuner implements FragmentTuner {
-        @Override
-        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
-
-            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(dirType != TYPE_RECENT_OPEN);
-
-            menu.findItem(R.id.menu_share).setVisible(true);
-            menu.findItem(R.id.menu_delete).setVisible(canDelete);
-
-            menu.findItem(R.id.menu_open).setVisible(false);
-            menu.findItem(R.id.menu_copy_to).setVisible(true);
-            menu.findItem(R.id.menu_move_to).setVisible(true);
-        }
-
-        @Override
-        public void afterActivityCreated(DirectoryFragment fragment) {}
-    }
-
     boolean isSelected(int position) {
         return mSelectionManager.getSelection().contains(position);
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index aae5269..18957ee 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -86,7 +86,7 @@
         mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
 
         if (!mShowAsDialog) {
-            setTheme(R.style.DocumentsNonDialogTheme);
+            setTheme(R.style.DocumentsFullScreenTheme);
         }
 
         if (mShowAsDialog) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index c06ea0a..d4c3ba3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -38,9 +38,7 @@
      * Returns true if event was triggered by a finger or stylus touch.
      */
     static boolean isTouchEvent(MotionEvent e) {
-        return isTouchType(e.getToolType(0))
-                // Temporarily work around uiautomator's missing tool type support.
-                || isUnknownType(e.getToolType(0));
+        return isTouchType(e.getToolType(0));
     }
 
     /**
@@ -51,7 +49,7 @@
     }
 
     /**
-     * Returns true if type is finger or stylus.
+     * Returns true if event was triggered by a finger or stylus touch.
      */
     static boolean isTouchType(int toolType) {
         return toolType == MotionEvent.TOOL_TYPE_FINGER
@@ -59,13 +57,6 @@
     }
 
     /**
-     * Returns true if type is unknown.
-     */
-    static boolean isUnknownType(int toolType) {
-        return toolType == MotionEvent.TOOL_TYPE_UNKNOWN;
-    }
-
-    /**
      * Returns true if event was triggered by a finger or stylus touch.
      */
     static boolean isActionDown(MotionEvent e) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 3b985ec..627ba75 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -334,12 +334,12 @@
                 startActivity(intent);
                 return;
             } catch (SecurityException e) {
-                // carry on to regular view mode.
+                // Carry on to regular view mode.
                 Log.e(TAG, "Caught security error: " + e.getLocalizedMessage());
             }
         }
 
-        // fallback to traditional VIEW action...
+        // Fallback to traditional VIEW action...
         intent = new Intent(Intent.ACTION_VIEW);
         intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.setData(doc.derivedUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Menus.java b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
index 3f43a3d..5277d2b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Menus.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Menus.java
@@ -19,14 +19,14 @@
 import android.view.Menu;
 import android.view.MenuItem;
 
-final class Menus {
+public final class Menus {
 
     private Menus() {}
 
     /**
      * Disables hidden menu items so that they are not invokable via command shortcuts
      */
-    static void disableHiddenItems(Menu menu, MenuItem... exclusions) {
+    public static void disableHiddenItems(Menu menu, MenuItem... exclusions) {
         for (int i = 0; i < menu.size(); i++) {
             MenuItem item = menu.getItem(i);
             if (item.isVisible()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 6a424a6..605c530 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -92,6 +92,8 @@
                 intent.setClipData(mClipData);
 
                 return intent;
+            } else {
+                Log.e(TAG, "Can't resolve trusted quick view package: " + trustedPkg);
             }
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 0dcd02d..d75b6fd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -287,33 +287,24 @@
             super(context, 0);
 
             final List<RootItem> libraries = new ArrayList<>();
-            final List<RootItem> clouds = new ArrayList<>();
-            final List<RootItem> locals = new ArrayList<>();
+            final List<RootItem> others = new ArrayList<>();
 
-            for (RootInfo root : roots) {
-                RootItem item = new RootItem(root);
-                switch (root.derivedType) {
-                    case RootInfo.TYPE_LOCAL:
-                        locals.add(item);
-                        break;
-                    case RootInfo.TYPE_CLOUD:
-                        clouds.add(item);
-                        break;
-                    default:
-                        libraries.add(item);
-                        break;
+            for (final RootInfo root : roots) {
+                final RootItem item = new RootItem(root);
+                if (root.isLibrary()) {
+                    libraries.add(item);
+                } else {
+                    others.add(item);
                 }
             }
 
             final RootComparator comp = new RootComparator();
             Collections.sort(libraries, comp);
-            Collections.sort(locals, comp);
-            Collections.sort(clouds, comp);
+            Collections.sort(others, comp);
 
             addAll(libraries);
             add(new SpacerItem());
-            addAll(locals);
-            addAll(clouds);
+            addAll(others);
 
             if (includeApps != null) {
                 final PackageManager pm = context.getPackageManager();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
new file mode 100644
index 0000000..ca85cff
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.State.ACTION_BROWSE;
+import static com.android.documentsui.State.ACTION_MANAGE;
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.os.SystemProperties;
+import android.view.Menu;
+import android.view.MenuItem;
+
+import com.android.documentsui.DirectoryFragment;
+import com.android.documentsui.Menus;
+import com.android.documentsui.R;
+import com.android.documentsui.State;
+
+/**
+ * Providers support for specializing the DirectoryFragment to the "host" Activity.
+ * Feel free to expand the role of this class to handle other specializations.
+ */
+public abstract class FragmentTuner {
+    public static FragmentTuner pick(State state) {
+        switch (state.action) {
+            case ACTION_BROWSE:
+                return new FilesTuner();
+            case ACTION_MANAGE:
+                return new ManageTuner();
+            default:
+                return new DocumentsTuner();
+        }
+    }
+
+    public abstract void updateActionMenu(Menu menu, int dirType, boolean canDelete);
+
+    /**
+     * Provides support for Platform specific specializations of DirectoryFragment.
+     */
+    private static final class DocumentsTuner extends FragmentTuner {
+        @Override
+        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+
+            boolean copyEnabled = dirType != DirectoryFragment.TYPE_RECENT_OPEN;
+            boolean moveEnabled =
+                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
+            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
+
+            final MenuItem open = menu.findItem(R.id.menu_open);
+            final MenuItem share = menu.findItem(R.id.menu_share);
+            final MenuItem delete = menu.findItem(R.id.menu_delete);
+            final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
+            final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
+
+            open.setVisible(true);
+            share.setVisible(false);
+            delete.setVisible(false);
+            copyTo.setVisible(copyEnabled);
+            copyTo.setEnabled(copyEnabled);
+            moveTo.setVisible(moveEnabled);
+            moveTo.setEnabled(moveEnabled);
+        }
+    }
+
+    /**
+     * Provides support for Platform specific specializations of DirectoryFragment.
+     */
+    private static final class ManageTuner extends FragmentTuner {
+
+        @Override
+        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+            checkArgument(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
+
+            boolean moveEnabled =
+                    SystemProperties.getBoolean("debug.documentsui.enable_move", false);
+            menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(true);
+
+            final MenuItem open = menu.findItem(R.id.menu_open);
+            final MenuItem share = menu.findItem(R.id.menu_share);
+            final MenuItem delete = menu.findItem(R.id.menu_delete);
+            final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
+            final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
+
+            open.setVisible(false);
+            share.setVisible(false);
+            delete.setVisible(canDelete);
+            copyTo.setVisible(true);
+            copyTo.setEnabled(true);
+            moveTo.setVisible(moveEnabled);
+            moveTo.setEnabled(moveEnabled);
+        }
+    }
+
+    /**
+     * Provides support for Files activity specific specializations of DirectoryFragment.
+     */
+    private static final class FilesTuner extends FragmentTuner {
+        @Override
+        public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+
+            MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
+            MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
+            copy.setEnabled(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
+
+            menu.findItem(R.id.menu_share).setVisible(true);
+            menu.findItem(R.id.menu_delete).setVisible(canDelete);
+
+            menu.findItem(R.id.menu_open).setVisible(false);
+            menu.findItem(R.id.menu_copy_to).setVisible(true);
+            menu.findItem(R.id.menu_move_to).setVisible(true);
+
+            Menus.disableHiddenItems(menu, copy, paste);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 17e6a80..501392c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -51,7 +51,8 @@
     public static final int TYPE_RECENTS = 4;
     public static final int TYPE_DOWNLOADS = 5;
     public static final int TYPE_LOCAL = 6;
-    public static final int TYPE_CLOUD = 7;
+    public static final int TYPE_MTP = 7;
+    public static final int TYPE_CLOUD = 8;
 
     public String authority;
     public String rootId;
@@ -184,6 +185,8 @@
             derivedType = TYPE_AUDIO;
         } else if (isRecents()) {
             derivedType = TYPE_RECENTS;
+        } else if (isMtp()) {
+            derivedType = TYPE_MTP;
         } else {
             derivedType = TYPE_CLOUD;
         }
@@ -216,6 +219,15 @@
                 && "audio_root".equals(rootId);
     }
 
+    public boolean isMtp() {
+        return "com.android.mtp.documents".equals(authority);
+    }
+
+    public boolean isLibrary() {
+        return derivedType == TYPE_IMAGES || derivedType == TYPE_VIDEO || derivedType == TYPE_AUDIO
+                || derivedType == TYPE_RECENTS || derivedType == TYPE_DOWNLOADS;
+    }
+
     @Override
     public String toString() {
         return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk
index 3f191a9..2a540d4 100644
--- a/packages/DocumentsUI/tests/Android.mk
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -3,11 +3,12 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
+#LOCAL_SDK_VERSION := current
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target guava
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target guava ub-uiautomator
 
 LOCAL_PACKAGE_NAME := DocumentsUITests
 LOCAL_INSTRUMENTATION_FOR := DocumentsUI
@@ -15,3 +16,4 @@
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
new file mode 100644
index 0000000..1f4b751
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.content.Intent;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.Configurator;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.view.MotionEvent;
+
+import java.util.concurrent.TimeoutException;
+
+public class FilesActivityUiTest extends InstrumentationTestCase {
+
+    private static final String TAG = "FilesActivityUiTest";
+    private static final String TARGET_PKG = "com.android.documentsui";
+    private static final String LAUNCHER_PKG = "com.android.launcher";
+    private static final int ONE_SECOND = 1000;
+    private static final int FIVE_SECONDS = 5 * ONE_SECOND;
+
+    private ActionBar mBar;
+    private UiDevice mDevice;
+    private Context mContext;
+
+    public void setUp() throws TimeoutException {
+        // Initialize UiDevice instance.
+        mDevice = UiDevice.getInstance(getInstrumentation());
+
+        Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
+
+        // Start from the home screen.
+        mDevice.pressHome();
+        mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), FIVE_SECONDS);
+
+        // Launch app.
+        mContext = getInstrumentation().getContext();
+        Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(TARGET_PKG);
+        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        mContext.startActivity(intent);
+
+        // Wait for the app to appear.
+        mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), FIVE_SECONDS);
+        mDevice.waitForIdle();
+
+        mBar = new ActionBar();
+    }
+
+    public void testSwitchMode() throws Exception {
+        UiObject2 mode = mBar.gridMode(100);
+        if (mode != null) {
+            mode.click();
+            assertNotNull(mBar.listMode(ONE_SECOND));
+        } else {
+            mBar.listMode(100).click();
+            assertNotNull(mBar.gridMode(ONE_SECOND));
+        }
+    }
+
+    private class ActionBar {
+
+        public UiObject2 gridMode(int timeout) {
+            // Note that we're using By.desc rather than By.res, because of b/25285770
+            BySelector selector = By.desc("Grid view");
+            if (timeout > 0) {
+                mDevice.wait(Until.findObject(selector), timeout);
+            }
+            return mDevice.findObject(selector);
+        }
+
+        public UiObject2 listMode(int timeout) {
+            // Note that we're using By.desc rather than By.res, because of b/25285770
+            BySelector selector = By.desc("List view");
+            if (timeout > 0) {
+                mDevice.wait(Until.findObject(selector), timeout);
+            }
+            return mDevice.findObject(selector);
+        }
+    }
+}
diff --git a/packages/InputDevices/res/raw/keyboard_layout_english_us_workman.kcm b/packages/InputDevices/res/raw/keyboard_layout_english_us_workman.kcm
new file mode 100644
index 0000000..fe82c8d
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_english_us_workman.kcm
@@ -0,0 +1,334 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# English (US), Workman keyboard layout.
+# Unlike the default (generic) keyboard layout, English (US) does not contain any
+# special ALT characters.
+#
+
+type OVERLAY
+
+map key 17 D
+map key 18 R
+map key 19 W
+map key 20 B
+map key 21 J
+map key 22 F
+map key 23 U
+map key 24 P
+map key 25 SEMICOLON
+map key 32 H
+map key 33 T
+map key 34 G
+map key 35 Y
+map key 36 N
+map key 37 E
+map key 38 O
+map key 39 I
+map key 46 M
+map key 47 C
+map key 48 V
+map key 49 K
+map key 50 L
+
+### ROW 1
+
+key GRAVE {
+    label:                              '`'
+    base:                               '`'
+    shift:                              '~'
+}
+
+key 1 {
+    label:                              '1'
+    base:                               '1'
+    shift:                              '!'
+}
+
+key 2 {
+    label:                              '2'
+    base:                               '2'
+    shift:                              '@'
+}
+
+key 3 {
+    label:                              '3'
+    base:                               '3'
+    shift:                              '#'
+}
+
+key 4 {
+    label:                              '4'
+    base:                               '4'
+    shift:                              '$'
+}
+
+key 5 {
+    label:                              '5'
+    base:                               '5'
+    shift:                              '%'
+}
+
+key 6 {
+    label:                              '6'
+    base:                               '6'
+    shift:                              '^'
+}
+
+key 7 {
+    label:                              '7'
+    base:                               '7'
+    shift:                              '&'
+}
+
+key 8 {
+    label:                              '8'
+    base:                               '8'
+    shift:                              '*'
+}
+
+key 9 {
+    label:                              '9'
+    base:                               '9'
+    shift:                              '('
+}
+
+key 0 {
+    label:                              '0'
+    base:                               '0'
+    shift:                              ')'
+}
+
+key MINUS {
+    label:                              '-'
+    base:                               '-'
+    shift:                              '_'
+}
+
+key EQUALS {
+    label:                              '='
+    base:                               '='
+    shift:                              '+'
+}
+
+### ROW 2
+
+key Q {
+    label:                              'Q'
+    base:                               'q'
+    shift, capslock:                    'Q'
+}
+
+key D {
+    label:                              'D'
+    base:                               'd'
+    shift, capslock:                    'D'
+}
+
+key R {
+    label:                              'R'
+    base:                               'r'
+    shift, capslock:                    'R'
+}
+
+key W {
+    label:                              'W'
+    base:                               'w'
+    shift, capslock:                    'W'
+}
+
+key B {
+    label:                              'B'
+    base:                               'b'
+    shift, capslock:                    'B'
+}
+
+key J {
+    label:                              'J'
+    base:                               'j'
+    shift, capslock:                    'J'
+}
+
+key F {
+    label:                              'F'
+    base:                               'f'
+    shift, capslock:                    'F'
+}
+
+key U {
+    label:                              'U'
+    base:                               'u'
+    shift, capslock:                    'U'
+}
+
+key P {
+    label:                              'P'
+    base:                               'p'
+    shift, capslock:                    'P'
+}
+
+key SEMICOLON {
+    label:                              ';'
+    base:                               ';'
+    shift, capslock:                    ':'
+}
+
+key LEFT_BRACKET {
+    label:                              '['
+    base:                               '['
+    shift:                              '{'
+}
+
+key RIGHT_BRACKET {
+    label:                              ']'
+    base:                               ']'
+    shift:                              '}'
+}
+
+key BACKSLASH {
+    label:                              '\\'
+    base:                               '\\'
+    shift:                              '|'
+}
+
+### ROW 3
+
+key A {
+    label:                              'A'
+    base:                               'a'
+    shift, capslock:                    'A'
+}
+
+key S {
+    label:                              'S'
+    base:                               's'
+    shift, capslock:                    'S'
+}
+
+key H {
+    label:                              'H'
+    base:                               'h'
+    shift, capslock:                    'H'
+}
+
+key T {
+    label:                              'T'
+    base:                               't'
+    shift, capslock:                    'T'
+}
+
+key G {
+    label:                              'G'
+    base:                               'g'
+    shift, capslock:                    'G'
+}
+
+key Y {
+    label:                              'Y'
+    base:                               'y'
+    shift, capslock:                    'Y'
+}
+
+key N {
+    label:                              'N'
+    base:                               'n'
+    shift, capslock:                    'N'
+}
+
+key E {
+    label:                              'E'
+    base:                               'e'
+    shift, capslock:                    'E'
+}
+
+key O {
+    label:                              'O'
+    base:                               'o'
+    shift:                              'O'
+}
+
+key I {
+    label:                              'I'
+    base:                               'i'
+    shift, capslock:                    'I'
+}
+
+key APOSTROPHE {
+    label:                              '\''
+    base:                               '\''
+    shift:                              '"'
+}
+
+### ROW 4
+
+key Z {
+    label:                              'Z'
+    base:                               'z'
+    shift, capslock:                    'Z'
+}
+
+key X {
+    label:                              'X'
+    base:                               'x'
+    shift, capslock:                    'X'
+}
+
+key M {
+    label:                              'M'
+    base:                               'm'
+    shift, capslock:                    'M'
+}
+
+key C {
+    label:                              'C'
+    base:                               'c'
+    shift, capslock:                    'C'
+}
+
+key V {
+    label:                              'V'
+    base:                               'v'
+    shift, capslock:                    'V'
+}
+
+key K {
+    label:                              'K'
+    base:                               'k'
+    shift, capslock:                    'K'
+}
+
+key L {
+    label:                              'L'
+    base:                               'l'
+    shift, capslock:                    'L'
+}
+
+key COMMA {
+    label:                              ','
+    base:                               ','
+    shift:                              '<'
+}
+
+key PERIOD {
+    label:                              '.'
+    base:                               '.'
+    shift:                              '>'
+}
+
+key SLASH {
+    label:                              '/'
+    base:                               '/'
+    shift:                              '?'
+}
diff --git a/packages/InputDevices/res/values-af/strings.xml b/packages/InputDevices/res/values-af/strings.xml
index d67a9fd..a36d01e 100644
--- a/packages/InputDevices/res/values-af/strings.xml
+++ b/packages/InputDevices/res/values-af/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engels (VS), internasionale styl"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engels (VS), Colemak-styl"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engels (VS), Dvorak-styl"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engels (VSA), Workman-styl"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Duits"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Frans"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Frans (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-am/strings.xml b/packages/InputDevices/res/values-am/strings.xml
index 3e84794..3186add 100644
--- a/packages/InputDevices/res/values-am/strings.xml
+++ b/packages/InputDevices/res/values-am/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"እንግሊዘኛ (ዩ. ኤስ.)፣ አለም አቀፍ ቅጥ"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"እንግሊዘኛ (ዩ. ኤስ.)፣ የኮልማርክ ቅጥ"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"እንግሊዘኛ (ዩ. ኤስ.)፣ የድቮራክ ቅጥ"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"እንግሊዝኛ (አሜሪካ)፣ የሥራሰው ቅጥ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ጀርመን"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ፈረንሳይኛ"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ፈረንሳይኛ (ካናዳ)"</string>
diff --git a/packages/InputDevices/res/values-ar/strings.xml b/packages/InputDevices/res/values-ar/strings.xml
index a922a46..1d3d9f5 100644
--- a/packages/InputDevices/res/values-ar/strings.xml
+++ b/packages/InputDevices/res/values-ar/strings.xml
@@ -8,6 +8,7 @@
     <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">"‏الإنجليزية (الولايات المتحدة)، نمط Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"الإنجليزية (الولايات المتحدة)، الحرفيّون"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"الألمانية"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"الفرنسية"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"الفرنسية (كندا)"</string>
diff --git a/packages/InputDevices/res/values-az-rAZ/strings.xml b/packages/InputDevices/res/values-az-rAZ/strings.xml
index d69059c..25d7c91 100644
--- a/packages/InputDevices/res/values-az-rAZ/strings.xml
+++ b/packages/InputDevices/res/values-az-rAZ/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"İngilis (ABŞ), Beynəlxalq üslub"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"İngilis (ABŞ), Colemak üslubu"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"İngilis (ABŞ), Dvorak üslubu"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"İngilis dili (ABŞ), Workman üslubu"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alman"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransız"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransız dili (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-bg/strings.xml b/packages/InputDevices/res/values-bg/strings.xml
index d68a347..e5e2c96 100644
--- a/packages/InputDevices/res/values-bg/strings.xml
+++ b/packages/InputDevices/res/values-bg/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"англ. (САЩ) – стил „Mеждународна“"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"английски (САЩ) – стил „Коулмак“"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"английски (САЩ) – стил „Дворак“"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"англ. (САЩ) – стил „Работническа“"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"немски"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"френски"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"френски (Канада)"</string>
diff --git a/packages/InputDevices/res/values-bn-rBD/strings.xml b/packages/InputDevices/res/values-bn-rBD/strings.xml
index 1676a95..a0ce313 100644
--- a/packages/InputDevices/res/values-bn-rBD/strings.xml
+++ b/packages/InputDevices/res/values-bn-rBD/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ইংরেজি (US), আন্তর্জাতিক শৈলী"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ইংরেজি (US), কোলেম্যাক শৈলী"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ইংরেজি (US), ডিভোরাক শৈলী"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ইংরেজি (US), ওয়ার্কম্যান শৈলী"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"জার্মান"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ফরাসী"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ফরাসী (কানাডা)"</string>
diff --git a/packages/InputDevices/res/values-ca/strings.xml b/packages/InputDevices/res/values-ca/strings.xml
index 6baa5b8..ee25a74 100644
--- a/packages/InputDevices/res/values-ca/strings.xml
+++ b/packages/InputDevices/res/values-ca/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglès (EUA), estil internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglès (EUA), estil Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglès (EUA), estil Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglès (EUA), estil Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemany"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francès"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francès (Canadà)"</string>
diff --git a/packages/InputDevices/res/values-cs/strings.xml b/packages/InputDevices/res/values-cs/strings.xml
index 1c502fe..3e7b9c8 100644
--- a/packages/InputDevices/res/values-cs/strings.xml
+++ b/packages/InputDevices/res/values-cs/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"anglické (USA), mezinárodní"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"anglické (USA), styl Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"anglické (USA), styl Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"anglické (USA), styl Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"německé"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"francouzské"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francouzské (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-da/strings.xml b/packages/InputDevices/res/values-da/strings.xml
index 043a5b3..228c51a 100644
--- a/packages/InputDevices/res/values-da/strings.xml
+++ b/packages/InputDevices/res/values-da/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelsk (USA), international stil"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelsk (USA), Colemak-stil"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelsk (USA), Dvorak-stil"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelsk (USA), Workman-stil"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tysk"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransk"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransk (Canada)"</string>
diff --git a/packages/InputDevices/res/values-de/strings.xml b/packages/InputDevices/res/values-de/strings.xml
index 40722f6..6af0030 100644
--- a/packages/InputDevices/res/values-de/strings.xml
+++ b/packages/InputDevices/res/values-de/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Englisch (USA), international"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Englisch (USA), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Englisch (USA), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Englisch (USA), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Deutsch"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Französisch"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Französisch (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-el/strings.xml b/packages/InputDevices/res/values-el/strings.xml
index 025a288..da6dca2 100644
--- a/packages/InputDevices/res/values-el/strings.xml
+++ b/packages/InputDevices/res/values-el/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Αγγλικά (ΗΠΑ), τύπου International"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Αγγλικά (ΗΠΑ), τύπου Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Αγγλικά (ΗΠΑ), τύπου Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Αγγλικά (ΗΠΑ), στυλ Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Γερμανικά"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Γαλλικά"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Γαλλικά (Καναδά)"</string>
diff --git a/packages/InputDevices/res/values-en-rAU/strings.xml b/packages/InputDevices/res/values-en-rAU/strings.xml
index d5797a0..01c2979 100644
--- a/packages/InputDevices/res/values-en-rAU/strings.xml
+++ b/packages/InputDevices/res/values-en-rAU/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"English (US), International style"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"English (US), Colemak style"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"English (US), Dvorak style"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"English (US), Workman style"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"German"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"French"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"French (Canada)"</string>
diff --git a/packages/InputDevices/res/values-en-rGB/strings.xml b/packages/InputDevices/res/values-en-rGB/strings.xml
index d5797a0..01c2979 100644
--- a/packages/InputDevices/res/values-en-rGB/strings.xml
+++ b/packages/InputDevices/res/values-en-rGB/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"English (US), International style"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"English (US), Colemak style"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"English (US), Dvorak style"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"English (US), Workman style"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"German"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"French"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"French (Canada)"</string>
diff --git a/packages/InputDevices/res/values-en-rIN/strings.xml b/packages/InputDevices/res/values-en-rIN/strings.xml
index d5797a0..01c2979 100644
--- a/packages/InputDevices/res/values-en-rIN/strings.xml
+++ b/packages/InputDevices/res/values-en-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"English (US), International style"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"English (US), Colemak style"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"English (US), Dvorak style"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"English (US), Workman style"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"German"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"French"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"French (Canada)"</string>
diff --git a/packages/InputDevices/res/values-es-rUS/strings.xml b/packages/InputDevices/res/values-es-rUS/strings.xml
index 0a9d2f3..6acf07b 100644
--- a/packages/InputDevices/res/values-es-rUS/strings.xml
+++ b/packages/InputDevices/res/values-es-rUS/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EE. UU.), internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EE. UU.), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EE. UU.), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglés (EE. UU.), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemán"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francés"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francés (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-es/strings.xml b/packages/InputDevices/res/values-es/strings.xml
index 6e41abf..af1492a 100644
--- a/packages/InputDevices/res/values-es/strings.xml
+++ b/packages/InputDevices/res/values-es/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EE.UU.), estilo internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EE.UU.), estilo Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EE.UU.), estilo Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglés (EE. UU.) estilo Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemán"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francés"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francés (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-et-rEE/strings.xml b/packages/InputDevices/res/values-et-rEE/strings.xml
index 0d931ce..d03b82e 100644
--- a/packages/InputDevices/res/values-et-rEE/strings.xml
+++ b/packages/InputDevices/res/values-et-rEE/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglise (USA), rahvusvaheline stiil"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglise (USA), Colemaki stiil"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglise (USA), Dvoraki stiil"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglise (USA), Workmani stiil"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Saksa"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Prantsuse"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Prantsuse (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-eu-rES/strings.xml b/packages/InputDevices/res/values-eu-rES/strings.xml
index d4d7b6a..d18c6f8 100644
--- a/packages/InputDevices/res/values-eu-rES/strings.xml
+++ b/packages/InputDevices/res/values-eu-rES/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Ingelesa (AEB), nazioarteko estiloa"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Ingelesa (AEB), Colemak estiloa"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Ingelesa (AEB), Dvorak estiloa"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Ingelesa (AEB), Workman estiloa"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemaniarra"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Frantsesa"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Frantsesa (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-fa/strings.xml b/packages/InputDevices/res/values-fa/strings.xml
index e87fbad..f2848a9 100644
--- a/packages/InputDevices/res/values-fa/strings.xml
+++ b/packages/InputDevices/res/values-fa/strings.xml
@@ -8,6 +8,7 @@
     <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">"‏انگلیسی (ایالات متحده)، سبک Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"انگلیسی (ایالات متحده)، سبک ورک‌من"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"آلمانی"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"فرانسوی"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"فرانسوی (کانادا)‏"</string>
diff --git a/packages/InputDevices/res/values-fi/strings.xml b/packages/InputDevices/res/values-fi/strings.xml
index 5b39dfd..284efc8 100644
--- a/packages/InputDevices/res/values-fi/strings.xml
+++ b/packages/InputDevices/res/values-fi/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"englanti (Yhdysvallat), kansainvälinen"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"englanti (Yhdysvallat), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"englanti (Yhdysvallat), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"englanti (Yhdysvallat), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"saksa"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ranska"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ranska (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-fr-rCA/strings.xml b/packages/InputDevices/res/values-fr-rCA/strings.xml
index 9973918..b26a0ea 100644
--- a/packages/InputDevices/res/values-fr-rCA/strings.xml
+++ b/packages/InputDevices/res/values-fr-rCA/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglais (États-Unis), international"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglais (États-Unis), type Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglais (États-Unis), type Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglais (États-Unis), style Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Allemand"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Français"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Français (Canada)"</string>
diff --git a/packages/InputDevices/res/values-fr/strings.xml b/packages/InputDevices/res/values-fr/strings.xml
index fa2977b..a428a23 100644
--- a/packages/InputDevices/res/values-fr/strings.xml
+++ b/packages/InputDevices/res/values-fr/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglais (États-Unis), international"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglais (États-Unis), type Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglais (États-Unis), type Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglais (États-Unis), style Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Allemand"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Français"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Français (Canada)"</string>
diff --git a/packages/InputDevices/res/values-gl-rES/strings.xml b/packages/InputDevices/res/values-gl-rES/strings.xml
index d9babd5..bb0f2a0 100644
--- a/packages/InputDevices/res/values-gl-rES/strings.xml
+++ b/packages/InputDevices/res/values-gl-rES/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglés (EUA), estilo internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglés (EUA), estilo Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglés (EUA), estilo Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglés (EUA), estilo Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemán"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francés"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francés (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-gu-rIN/strings.xml b/packages/InputDevices/res/values-gu-rIN/strings.xml
index 3abae49..e83b0ca 100644
--- a/packages/InputDevices/res/values-gu-rIN/strings.xml
+++ b/packages/InputDevices/res/values-gu-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"અંગ્રેજી (યુએસ), આંતરરાષ્ટ્રીય શૈલી"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"અંગ્રેજી (યુએસ), કોલેમેક શૈલી"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"અંગ્રેજી (યુએસ), ડ્વોરક શૈલી"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"અંગ્રેજી (યુએસ), વર્કમૅન શૈલી"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"જર્મન"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ફ્રેન્ચ"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ફ્રેન્ચ (કેનેડા)"</string>
diff --git a/packages/InputDevices/res/values-hi/strings.xml b/packages/InputDevices/res/values-hi/strings.xml
index fcd7f84..41966e4 100644
--- a/packages/InputDevices/res/values-hi/strings.xml
+++ b/packages/InputDevices/res/values-hi/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"अंग्रेज़ी (यूएस), अंतर्राष्ट्रीय शैली"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"अंग्रेज़ी (यूएस), कोलमैक शैली"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"अंग्रेज़ी (यूएस), ड्वोरक शैली"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"अंग्रेज़ी (यूएस), वर्कमैन शैली"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"जर्मन"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"फ़्रांसीसी"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"फ़्रांसीसी (कनाडा)"</string>
diff --git a/packages/InputDevices/res/values-hr/strings.xml b/packages/InputDevices/res/values-hr/strings.xml
index bad973d..27066ad 100644
--- a/packages/InputDevices/res/values-hr/strings.xml
+++ b/packages/InputDevices/res/values-hr/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"engleska (SAD), međunarodna"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"engleska (SAD), Colemakov raspored"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"engleska (SAD), Dvorakov raspored"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engleska (SAD), raspored Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"njemačka"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"francuska"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francuska (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-hu/strings.xml b/packages/InputDevices/res/values-hu/strings.xml
index 510591d..6fbc3eb 100644
--- a/packages/InputDevices/res/values-hu/strings.xml
+++ b/packages/InputDevices/res/values-hu/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"angol (USA), nemzetközi stílus"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"angol (USA), Colemak-stílus"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"angol (USA), Dvorak-stílus"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"angol (USA), „Workman” stílus"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"német"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"francia"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francia (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-hy-rAM/strings.xml b/packages/InputDevices/res/values-hy-rAM/strings.xml
index 9ffa8bb..0d11645 100644
--- a/packages/InputDevices/res/values-hy-rAM/strings.xml
+++ b/packages/InputDevices/res/values-hy-rAM/strings.xml
@@ -8,6 +8,7 @@
     <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">"Անգլերեն (ԱՄՆ), Dvorak տեսակ"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Անգլերեն (ԱՄՆ), Workman տեսակ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Գերմաներեն"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Ֆրանսերեն"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Ֆրանսերեն (Կանադա)"</string>
diff --git a/packages/InputDevices/res/values-in/strings.xml b/packages/InputDevices/res/values-in/strings.xml
index fccfa67..b2cbd6e 100644
--- a/packages/InputDevices/res/values-in/strings.xml
+++ b/packages/InputDevices/res/values-in/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inggris (AS), gaya Internasional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inggris (AS), gaya Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inggris (AS), gaya Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inggris (AS), gaya Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Jerman"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Prancis"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Prancis (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-is-rIS/strings.xml b/packages/InputDevices/res/values-is-rIS/strings.xml
index e48fa49..de91275 100644
--- a/packages/InputDevices/res/values-is-rIS/strings.xml
+++ b/packages/InputDevices/res/values-is-rIS/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Enskt (Bandaríkin), alþjóðlegt"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Enskt (Bandaríkin), Colemak-stíll"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Enskt (Bandaríkin), Dvorak-stíll"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Enska (Bandaríkin), Workman-stíll"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Þýskt"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-it/strings.xml b/packages/InputDevices/res/values-it/strings.xml
index 83dba70..c1c7faa 100644
--- a/packages/InputDevices/res/values-it/strings.xml
+++ b/packages/InputDevices/res/values-it/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglese (USA), stile internazionale"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglese (USA), stile Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglese (USA), stile Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglese (USA), stile Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tedesco"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francese"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francese (Canada)"</string>
diff --git a/packages/InputDevices/res/values-iw/strings.xml b/packages/InputDevices/res/values-iw/strings.xml
index 26fe662..b3bd576 100644
--- a/packages/InputDevices/res/values-iw/strings.xml
+++ b/packages/InputDevices/res/values-iw/strings.xml
@@ -8,6 +8,7 @@
     <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">"‏אנגלית (ארה\"ב), סגנון Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"‏אנגלית (ארה\"ב), סגנון Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"גרמנית"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"צרפתית"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"צרפתית (קנדה)"</string>
diff --git a/packages/InputDevices/res/values-ja/strings.xml b/packages/InputDevices/res/values-ja/strings.xml
index e2b154d..2b3daf5 100644
--- a/packages/InputDevices/res/values-ja/strings.xml
+++ b/packages/InputDevices/res/values-ja/strings.xml
@@ -8,6 +8,7 @@
     <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">"英語(アメリカ)、Dvorak配列"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英語(アメリカ)、Workman配列"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ドイツ語"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"フランス語"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"フランス語(カナダ)"</string>
diff --git a/packages/InputDevices/res/values-ka-rGE/strings.xml b/packages/InputDevices/res/values-ka-rGE/strings.xml
index eff4b04..66d147e 100644
--- a/packages/InputDevices/res/values-ka-rGE/strings.xml
+++ b/packages/InputDevices/res/values-ka-rGE/strings.xml
@@ -8,6 +8,7 @@
     <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">"ინგლისური (აშშ), Dvorak სტილი"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ინგლისური (აშშ), Workman სტილი"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"გერმანული"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ფრანგული"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ფრანგული (კანადა)"</string>
diff --git a/packages/InputDevices/res/values-kk-rKZ/strings.xml b/packages/InputDevices/res/values-kk-rKZ/strings.xml
index 7086bf7..d253542 100644
--- a/packages/InputDevices/res/values-kk-rKZ/strings.xml
+++ b/packages/InputDevices/res/values-kk-rKZ/strings.xml
@@ -8,6 +8,7 @@
     <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">"Ағылшын (АҚШ), Dvorak стилі"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Ағылшын (АҚШ), Workman стилі"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Неміс"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Француз"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Француз (Канада)"</string>
diff --git a/packages/InputDevices/res/values-km-rKH/strings.xml b/packages/InputDevices/res/values-km-rKH/strings.xml
index 60a28b1..acd01ee 100644
--- a/packages/InputDevices/res/values-km-rKH/strings.xml
+++ b/packages/InputDevices/res/values-km-rKH/strings.xml
@@ -8,6 +8,7 @@
     <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">"អង់គ្លេស (សហរដ្ឋ​អាមេរិក​)​, ​​រចនាប័ទ្ម Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"អង់គ្លេស (អាមេរិក) រចនាបទ Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"អាល្លឺម៉ង់"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"បារាំង"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"បារាំង (កាណាដា​)"</string>
diff --git a/packages/InputDevices/res/values-kn-rIN/strings.xml b/packages/InputDevices/res/values-kn-rIN/strings.xml
index 6b43517..243e6597 100644
--- a/packages/InputDevices/res/values-kn-rIN/strings.xml
+++ b/packages/InputDevices/res/values-kn-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ಇಂಗ್ಲಿಷ್ (US), ಅಂತರರಾಷ್ಟ್ರೀಯ ಶೈಲಿ"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ಇಂಗ್ಲಿಷ್ (US), ಕೋಲ್ಮಾರ್ಕ್ ಶೈಲಿ"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ಇಂಗ್ಲಿಷ್ (US), ಡಿವೊರಾಕ್ ಶೈಲಿ"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ಇಂಗ್ಲೀಷ್ (US), ವರ್ಕ್‌ಮನ್ ಶೈಲಿ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ಜರ್ಮನ್"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ಫ್ರೆಂಚ್"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ಫ್ರೆಂಚ್‌ (ಕೆನಡಾ)"</string>
diff --git a/packages/InputDevices/res/values-ko/strings.xml b/packages/InputDevices/res/values-ko/strings.xml
index 3f563d1..7758210 100644
--- a/packages/InputDevices/res/values-ko/strings.xml
+++ b/packages/InputDevices/res/values-ko/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"영어(미국), 글로벌 스타일"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"영어(미국), 콜맥 스타일"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"영어(미국), 드보락 스타일"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"영어(미국), 워크맨 스타일"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"독일어"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"프랑스어"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"프랑스어(캐나다)"</string>
diff --git a/packages/InputDevices/res/values-ky-rKG/strings.xml b/packages/InputDevices/res/values-ky-rKG/strings.xml
index 0828222..aa74733 100644
--- a/packages/InputDevices/res/values-ky-rKG/strings.xml
+++ b/packages/InputDevices/res/values-ky-rKG/strings.xml
@@ -8,6 +8,7 @@
     <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">"Англис (АКШ), Dvorak стили"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Англисче (АКШ), Workman стили"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Немис"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Француз"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Француз (Канада)"</string>
diff --git a/packages/InputDevices/res/values-lo-rLA/strings.xml b/packages/InputDevices/res/values-lo-rLA/strings.xml
index fb3fe17..05b1b83 100644
--- a/packages/InputDevices/res/values-lo-rLA/strings.xml
+++ b/packages/InputDevices/res/values-lo-rLA/strings.xml
@@ -8,6 +8,7 @@
     <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">"ອັງກິດ (ສະຫະລັດຯ), ແບບ Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ອັງກິດ (ສະຫະລັດ), ແບບຄົນ​ເຮັດ​ວຽກ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ເຢຍລະມັນ"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ຝຣັ່ງ"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ຝຣັ່ງ (ຄານາດາ)"</string>
diff --git a/packages/InputDevices/res/values-lt/strings.xml b/packages/InputDevices/res/values-lt/strings.xml
index d0eb1f6..1dae850 100644
--- a/packages/InputDevices/res/values-lt/strings.xml
+++ b/packages/InputDevices/res/values-lt/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Anglų k. (JAV), tarptautinis stilius"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Anglų k. (JAV), „Colemak“ stilius"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Anglų k. (JAV), „Dvorak“ stilius"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Anglų k. (JAV), „Workman“ stilius"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Vokiečių k."</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Prancūzų k."</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Prancūzų k. (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-lv/strings.xml b/packages/InputDevices/res/values-lv/strings.xml
index 0608bf0..96dc53b 100644
--- a/packages/InputDevices/res/values-lv/strings.xml
+++ b/packages/InputDevices/res/values-lv/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Angļu (ASV), starptautiska"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Angļu (ASV), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Angļu (ASV), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Angļu (ASV), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Vācu"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franču"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franču (Kanāda)"</string>
diff --git a/packages/InputDevices/res/values-mk-rMK/strings.xml b/packages/InputDevices/res/values-mk-rMK/strings.xml
index 8662984..2fae1cf 100644
--- a/packages/InputDevices/res/values-mk-rMK/strings.xml
+++ b/packages/InputDevices/res/values-mk-rMK/strings.xml
@@ -8,6 +8,7 @@
     <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">"Англиски (САД), Dvorak стил"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Англиски (САД), Workman стил"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Германски"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Француски"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Француски (Канада)"</string>
diff --git a/packages/InputDevices/res/values-ml-rIN/strings.xml b/packages/InputDevices/res/values-ml-rIN/strings.xml
index 4f846a0..0faa40e 100644
--- a/packages/InputDevices/res/values-ml-rIN/strings.xml
+++ b/packages/InputDevices/res/values-ml-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ഇംഗ്ലീഷ് (യു.എസ്), അന്തർദ്ദേശീയ ശൈലി"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ഇംഗ്ലീഷ് (യു.എസ്), കോൽമാക് ശൈലി"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ഇംഗ്ലീഷ് (യു.എസ്), ദ്വരോക്ക് ശൈലി"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ഇംഗ്ലീഷ് (യുഎസ്), വർക്ക്‌മാൻ ശൈലി"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ജര്‍‌മ്മന്‍‌"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ഫ്രഞ്ച്"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ഫ്രഞ്ച് (കാനഡ)"</string>
diff --git a/packages/InputDevices/res/values-mn-rMN/strings.xml b/packages/InputDevices/res/values-mn-rMN/strings.xml
index a28fd2a..f1354fe 100644
--- a/packages/InputDevices/res/values-mn-rMN/strings.xml
+++ b/packages/InputDevices/res/values-mn-rMN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Англи (АНУ), Олон улсын стиль"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Англи (АНУ), Колемак стиль"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Англи (АНУ), Дворак стиль"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Aнгли хэл (АНУ), Aжилчин загвар"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Герман"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Франц"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Франц (Канад)"</string>
diff --git a/packages/InputDevices/res/values-mr-rIN/strings.xml b/packages/InputDevices/res/values-mr-rIN/strings.xml
index 119ae6c..9ffcc70 100644
--- a/packages/InputDevices/res/values-mr-rIN/strings.xml
+++ b/packages/InputDevices/res/values-mr-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"इंग्रजी (यूएस), आंतरराष्‍ट्रीय शैली"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"इंग्रजी (यूएस), कोलमॅक शैली"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"इंग्रजी (यूएस), ड्वोरॅक शैली"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"इंग्रजी (यूएस), कामगार शैली"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"जर्मन"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"फ्रेंच"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"फ्रेंच (कॅनडा)"</string>
diff --git a/packages/InputDevices/res/values-ms-rMY/strings.xml b/packages/InputDevices/res/values-ms-rMY/strings.xml
index a1a6d00..04983e3 100644
--- a/packages/InputDevices/res/values-ms-rMY/strings.xml
+++ b/packages/InputDevices/res/values-ms-rMY/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Bahasa Inggeris (AS), gaya A/bangsa"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Bahasa Inggeris (AS), gaya Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Bahasa Inggeris (AS), gaya Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Bahasa Inggeris (AS), gaya Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Bahasa Jerman"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Bahasa Perancis"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Bahasa Perancis (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-my-rMM/strings.xml b/packages/InputDevices/res/values-my-rMM/strings.xml
index 91bdc55..f3762b4 100644
--- a/packages/InputDevices/res/values-my-rMM/strings.xml
+++ b/packages/InputDevices/res/values-my-rMM/strings.xml
@@ -8,6 +8,7 @@
     <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">"အင်္ဂလိပ် (ယူအက်စ်)၊Dvorak ပုံစံ"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"အင်္ဂလိပ် (ယူအက်စ်)၊ အလုပ်လုပ်သူ ပုံစံ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ဂျာမန်"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ပြင်သစ်"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ပြင်သစ် (ကနေဒါ)"</string>
diff --git a/packages/InputDevices/res/values-nb/strings.xml b/packages/InputDevices/res/values-nb/strings.xml
index ad4b704..37604e3 100644
--- a/packages/InputDevices/res/values-nb/strings.xml
+++ b/packages/InputDevices/res/values-nb/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelsk (USA), internasjonal stil"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelsk (USA), Colemak-stil"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelsk (USA), Dvorak-stil"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelsk (USA), workman-stil"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tysk"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransk"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransk (Canada)"</string>
diff --git a/packages/InputDevices/res/values-ne-rNP/strings.xml b/packages/InputDevices/res/values-ne-rNP/strings.xml
index 4e5c2b5..4c3dec3 100644
--- a/packages/InputDevices/res/values-ne-rNP/strings.xml
+++ b/packages/InputDevices/res/values-ne-rNP/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"अङ्ग्रेजी (अमेरिकी), अन्तर्राष्ट्रिय शैली"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"अङ्ग्रेजी (अमेरिकी), कोलमाक शैली"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"अङ्ग्रेजी (अमेरिकी), डेभोर्याक शैली"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"अंग्रेजी (अमेरिका), वर्कम्यान शैली"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"जर्मन"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"फ्रान्सेली"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"फ्रेंच (क्यानाडा)"</string>
diff --git a/packages/InputDevices/res/values-nl/strings.xml b/packages/InputDevices/res/values-nl/strings.xml
index c57251e..31ade05 100644
--- a/packages/InputDevices/res/values-nl/strings.xml
+++ b/packages/InputDevices/res/values-nl/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engels (VS), internationaal"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engels (VS), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engels (VS), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engels (VS), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Duits"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Frans"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Frans (Canada)"</string>
diff --git a/packages/InputDevices/res/values-pa-rIN/strings.xml b/packages/InputDevices/res/values-pa-rIN/strings.xml
index a885088..437352c 100644
--- a/packages/InputDevices/res/values-pa-rIN/strings.xml
+++ b/packages/InputDevices/res/values-pa-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ਅੰਗ੍ਰੇਜ਼ੀ (ਅਮਰੀਕਾ), ਅੰਤਰਰਾਸ਼ਟਰੀ ਸਟਾਈਲ"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ਅੰਗ੍ਰੇਜ਼ੀ (ਅਮਰੀਕਾ), ਕੋਲਮਾਰਕ ਸਟਾਈਲ"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ਅੰਗ੍ਰੇਜ਼ੀ (ਅਮਰੀਕਾ), ਵੋਰਕ ਸਟਾਈਲ"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ਅੰਗਰੇਜ਼ੀ (US), ਵਰਕਮੈਨ ਸਟਾਈਲ"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ਜਰਮਨ"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ਫਰਾਂਸੀਸੀ"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ਫ੍ਰੈਂਚ (ਕੈਨੇਡਾ)"</string>
diff --git a/packages/InputDevices/res/values-pl/strings.xml b/packages/InputDevices/res/values-pl/strings.xml
index 39fb3ec..2ae815e32 100644
--- a/packages/InputDevices/res/values-pl/strings.xml
+++ b/packages/InputDevices/res/values-pl/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Angielski (USA), międzynarodowy"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Angielski (USA), Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Angielski (USA), Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Angielski (USA), Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Niemiecki"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francuski"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francuski (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-pt-rBR/strings.xml b/packages/InputDevices/res/values-pt-rBR/strings.xml
index e9a0a38..a1503a4 100644
--- a/packages/InputDevices/res/values-pt-rBR/strings.xml
+++ b/packages/InputDevices/res/values-pt-rBR/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglês (EUA), estilo internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglês (EUA), estilo Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglês (EUA), estilo Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglês (EUA), estilo Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemão"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francês"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francês (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-pt-rPT/strings.xml b/packages/InputDevices/res/values-pt-rPT/strings.xml
index 3ac3b84..b806fc2 100644
--- a/packages/InputDevices/res/values-pt-rPT/strings.xml
+++ b/packages/InputDevices/res/values-pt-rPT/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglês (EUA), est. Internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglês (EUA), estilo Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglês (EUA), estilo Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglês (EUA), estilo Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemão"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francês"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francês (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-pt/strings.xml b/packages/InputDevices/res/values-pt/strings.xml
index e9a0a38..a1503a4 100644
--- a/packages/InputDevices/res/values-pt/strings.xml
+++ b/packages/InputDevices/res/values-pt/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglês (EUA), estilo internacional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglês (EUA), estilo Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglês (EUA), estilo Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Inglês (EUA), estilo Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Alemão"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Francês"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Francês (Canadá)"</string>
diff --git a/packages/InputDevices/res/values-ro/strings.xml b/packages/InputDevices/res/values-ro/strings.xml
index c2392b1..795e9a2 100644
--- a/packages/InputDevices/res/values-ro/strings.xml
+++ b/packages/InputDevices/res/values-ro/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engleză (SUA), stil internațional"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engleză (SUA), stil Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engleză (SUA), stil Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engleză (SUA), stil Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Germană"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franceză"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franceză (Canada)"</string>
diff --git a/packages/InputDevices/res/values-ru/strings.xml b/packages/InputDevices/res/values-ru/strings.xml
index 70ecf6e..ac4c81b 100644
--- a/packages/InputDevices/res/values-ru/strings.xml
+++ b/packages/InputDevices/res/values-ru/strings.xml
@@ -8,6 +8,7 @@
     <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">"английский (США, Dvorak)"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"английский (США, Workman)"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"немецкий"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"французский"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"французский (Канада)"</string>
diff --git a/packages/InputDevices/res/values-si-rLK/strings.xml b/packages/InputDevices/res/values-si-rLK/strings.xml
index 67563c4..945a097 100644
--- a/packages/InputDevices/res/values-si-rLK/strings.xml
+++ b/packages/InputDevices/res/values-si-rLK/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ඉංග්‍රීසි (US), අන්තර්ජාතික ආකාරය"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ඉංග්‍රීසි (US), Colemak ආකාරය"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ඉංග්‍රීසි (US), Dvorak ආකාරය"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ඉංග්‍රීසි (එ.ජ.), වර්ක්මන් ආකාරය"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ජර්මානු"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ප්‍රංශ"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ප්‍රංශ (කැනඩාව)"</string>
diff --git a/packages/InputDevices/res/values-sk/strings.xml b/packages/InputDevices/res/values-sk/strings.xml
index d2ee0cf..2e76024f 100644
--- a/packages/InputDevices/res/values-sk/strings.xml
+++ b/packages/InputDevices/res/values-sk/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"anglické (USA), medzinárodné"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"anglické (USA), štýl Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"anglické (USA), štýl Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"anglické (USA), štýl Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"nemecké"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"francúzske"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francúzske (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-sl/strings.xml b/packages/InputDevices/res/values-sl/strings.xml
index 38542ef..a643c8e 100644
--- a/packages/InputDevices/res/values-sl/strings.xml
+++ b/packages/InputDevices/res/values-sl/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"angleška (ZDA), mednarodni slog"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"angleška (ZDA), slog Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"angleška (ZDA), slog Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"angleška (ZDA), slog Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"nemška"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"francoska"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"francoska (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-sq-rAL/strings.xml b/packages/InputDevices/res/values-sq-rAL/strings.xml
index 2092926..8a9000d 100644
--- a/packages/InputDevices/res/values-sq-rAL/strings.xml
+++ b/packages/InputDevices/res/values-sq-rAL/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"anglisht (SHBA), stili \"ndërkombëtar\""</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"anglisht (SHBA), stili \"colemak\""</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"anglisht (SHBA), stili \"dvorak\""</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"anglisht (SHBA), stili \"workman\""</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"gjermanisht"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"frëngjisht"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"frëngjisht (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-sr/strings.xml b/packages/InputDevices/res/values-sr/strings.xml
index dd500e6..b06f6fc 100644
--- a/packages/InputDevices/res/values-sr/strings.xml
+++ b/packages/InputDevices/res/values-sr/strings.xml
@@ -8,6 +8,7 @@
     <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">"енглеска (САД), Dvorak стил"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"енглеска (САД), Workman стил"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"немачка"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"француска"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"француска (Канада)"</string>
diff --git a/packages/InputDevices/res/values-sv/strings.xml b/packages/InputDevices/res/values-sv/strings.xml
index c2406c0..89cb54e 100644
--- a/packages/InputDevices/res/values-sv/strings.xml
+++ b/packages/InputDevices/res/values-sv/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Engelskt (USA), internationellt"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Engelskt (USA), colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Engelskt (USA), dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Engelskt (USA), workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tyskt"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Franskt"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Franskt (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-sw/strings.xml b/packages/InputDevices/res/values-sw/strings.xml
index f71a696..1f447b0 100644
--- a/packages/InputDevices/res/values-sw/strings.xml
+++ b/packages/InputDevices/res/values-sw/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Kiingereza (Marekani), Muundo wa Kimataifa"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Kiingereza (Marekani), Muundo wa Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Kiingereza (Marekani), Muundo wa Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Kiingereza (US), mtindo wa Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Kijerumani"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Kifaransa"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Kifaransa (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-ta-rIN/strings.xml b/packages/InputDevices/res/values-ta-rIN/strings.xml
index 30d653d..32efe7b 100644
--- a/packages/InputDevices/res/values-ta-rIN/strings.xml
+++ b/packages/InputDevices/res/values-ta-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ஆங்கிலம் (யூஎஸ்), சர்வதேச நடை"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ஆங்கிலம் (யூஎஸ்), கோல்மாக் நடை"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ஆங்கிலம் (யூஎஸ்), டிவாரக் நடை"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ஆங்கிலம் (யூஎஸ்), வொர்க்மென் நடை"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"ஜெர்மன்"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ஃபிரெஞ்ச்"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ஃபிரெஞ்ச் (கனடா)"</string>
diff --git a/packages/InputDevices/res/values-te-rIN/strings.xml b/packages/InputDevices/res/values-te-rIN/strings.xml
index cc1b14d..e07d4c8 100644
--- a/packages/InputDevices/res/values-te-rIN/strings.xml
+++ b/packages/InputDevices/res/values-te-rIN/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"ఇంగ్లీష్ (US), అంతర్జాతీయ శైలి"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"ఇంగ్లీష్ (US), కొల్‌మాక్ శైలి"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"ఇంగ్లీష్ (US), ద్వోరక్ శైలి"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"ఆంగ్లం (US), వర్క్‌మాన్ శైలి"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"జర్మన్"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ఫ్రెంచ్"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ఫ్రెంచ్ (కెనడా)"</string>
diff --git a/packages/InputDevices/res/values-th/strings.xml b/packages/InputDevices/res/values-th/strings.xml
index 487b051..50dc1e4 100644
--- a/packages/InputDevices/res/values-th/strings.xml
+++ b/packages/InputDevices/res/values-th/strings.xml
@@ -8,6 +8,7 @@
     <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">"อังกฤษ (อเมริกัน), รูปแบบ Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"อังกฤษ (อเมริกัน), รูปแบบ Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"เยอรมัน"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"ฝรั่งเศส"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"ฝรั่งเศส (แคนาดา)"</string>
diff --git a/packages/InputDevices/res/values-tl/strings.xml b/packages/InputDevices/res/values-tl/strings.xml
index d7920ed..4bd857d 100644
--- a/packages/InputDevices/res/values-tl/strings.xml
+++ b/packages/InputDevices/res/values-tl/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Ingles (US), istilong International"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Ingles (US), istilong Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Ingles (US), istilong Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"English (US), Workman style"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"German"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"French"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"French (Canada)"</string>
diff --git a/packages/InputDevices/res/values-tr/strings.xml b/packages/InputDevices/res/values-tr/strings.xml
index c0c70be..a8d9a0f 100644
--- a/packages/InputDevices/res/values-tr/strings.xml
+++ b/packages/InputDevices/res/values-tr/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"İngilizce (ABD) Uluslararası stil"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"İngilizce (ABD) Colemak stili"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"İngilizce (ABD) Dvorak stili"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"İngilizce (ABD), Workman stili"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Almanca"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransızca"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransızca (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-uk/strings.xml b/packages/InputDevices/res/values-uk/strings.xml
index 43a3fe6..c818001 100644
--- a/packages/InputDevices/res/values-uk/strings.xml
+++ b/packages/InputDevices/res/values-uk/strings.xml
@@ -8,6 +8,7 @@
     <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>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"англійська (США), розкладка Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"німецька"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"французька"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"французька (Канада)"</string>
diff --git a/packages/InputDevices/res/values-ur-rPK/strings.xml b/packages/InputDevices/res/values-ur-rPK/strings.xml
index eee1eb2..3d2f618 100644
--- a/packages/InputDevices/res/values-ur-rPK/strings.xml
+++ b/packages/InputDevices/res/values-ur-rPK/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"انگریزی (امریکہ)، انٹرنیشنل سٹائل"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"انگریزی (امریکہ)، کول مارک سٹائل"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"انگریزی (امریکہ)، ڈوراک سٹائل"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"‏انگریزی (US)، ورک مین اسٹائل"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"جرمن"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"فرانسیسی"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"فرانسیسی (کینیڈا)"</string>
diff --git a/packages/InputDevices/res/values-uz-rUZ/strings.xml b/packages/InputDevices/res/values-uz-rUZ/strings.xml
index 3b6772b..9c55615 100644
--- a/packages/InputDevices/res/values-uz-rUZ/strings.xml
+++ b/packages/InputDevices/res/values-uz-rUZ/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Inglizcha (AQSH), xalqaro uslubda"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Inglizcha (AQSH), Kolemak uslubida"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Inglizcha (AQSH), Dvorak uslubida"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Ingliz (AQSH), ishchi uslubda"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Nemischa"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Fransuzcha"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Fransuzcha (Kanada)"</string>
diff --git a/packages/InputDevices/res/values-vi/strings.xml b/packages/InputDevices/res/values-vi/strings.xml
index a90c1cd..3ca715b 100644
--- a/packages/InputDevices/res/values-vi/strings.xml
+++ b/packages/InputDevices/res/values-vi/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"Tiếng Anh (Mỹ), kiểu Quốc tế"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"Tiếng Anh (Mỹ), kiểu Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"Tiếng Anh (Mỹ), kiểu Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"Tiếng Anh (Mỹ), kiểu Workman"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Tiếng Đức"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Tiếng Pháp"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Tiếng Pháp (Canada)"</string>
diff --git a/packages/InputDevices/res/values-zh-rCN/strings.xml b/packages/InputDevices/res/values-zh-rCN/strings.xml
index c050ebd..c61dccb 100644
--- a/packages/InputDevices/res/values-zh-rCN/strings.xml
+++ b/packages/InputDevices/res/values-zh-rCN/strings.xml
@@ -8,6 +8,7 @@
     <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">"英语(美国),Dvorak 风格"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英语(美国),Workman 风格"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"德语"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"法语"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"法语(加拿大)"</string>
diff --git a/packages/InputDevices/res/values-zh-rHK/strings.xml b/packages/InputDevices/res/values-zh-rHK/strings.xml
index ff5570e..9385df8 100644
--- a/packages/InputDevices/res/values-zh-rHK/strings.xml
+++ b/packages/InputDevices/res/values-zh-rHK/strings.xml
@@ -8,6 +8,7 @@
     <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">"英文 (美國),Dvorak 樣式"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英文 (美國),Workman 樣式"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"德文"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"法文"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"法文 (加拿大)"</string>
diff --git a/packages/InputDevices/res/values-zh-rTW/strings.xml b/packages/InputDevices/res/values-zh-rTW/strings.xml
index 859983d..89ef558 100644
--- a/packages/InputDevices/res/values-zh-rTW/strings.xml
+++ b/packages/InputDevices/res/values-zh-rTW/strings.xml
@@ -8,6 +8,7 @@
     <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">"英文 (美國),Dvorak 樣式"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"英文 (美國),Workman 樣式"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"德文"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"法文"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"法文 (加拿大)"</string>
diff --git a/packages/InputDevices/res/values-zu/strings.xml b/packages/InputDevices/res/values-zu/strings.xml
index 9f30f7a..0dcffb0 100644
--- a/packages/InputDevices/res/values-zu/strings.xml
+++ b/packages/InputDevices/res/values-zu/strings.xml
@@ -8,6 +8,7 @@
     <string name="keyboard_layout_english_us_intl" msgid="3705168594034233583">"I-English (US), isitayela sakwamanye amazwe"</string>
     <string name="keyboard_layout_english_us_colemak_label" msgid="4194969610343455380">"I-English (US), isitayela se-Colemak"</string>
     <string name="keyboard_layout_english_us_dvorak_label" msgid="793528923171145202">"I-English (US), isitayela se-Dvorak"</string>
+    <string name="keyboard_layout_english_us_workman_label" msgid="2944541595262173111">"I-English (US), isitayela sokusebenza"</string>
     <string name="keyboard_layout_german_label" msgid="8451565865467909999">"Isi-German"</string>
     <string name="keyboard_layout_french_label" msgid="813450119589383723">"Isi-French"</string>
     <string name="keyboard_layout_french_ca_label" msgid="365352601060604832">"Isi-French (Canada)"</string>
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 968961a..5644c9a 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -21,6 +21,9 @@
     <!-- US English (Dvorak style) keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_english_us_dvorak_label">English (US), Dvorak style</string>
 
+    <!-- US English (Workman style) keyboard layout label. [CHAR LIMIT=35] -->
+    <string name="keyboard_layout_english_us_workman_label">English (US), Workman style</string>
+
     <!-- German keyboard layout label. [CHAR LIMIT=35] -->
     <string name="keyboard_layout_german_label">German</string>
 
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index 6f7253c..a302162 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -20,6 +20,10 @@
             android:label="@string/keyboard_layout_english_us_dvorak_label"
             android:keyboardLayout="@raw/keyboard_layout_english_us_dvorak" />
 
+    <keyboard-layout android:name="keyboard_layout_english_us_workman"
+            android:label="@string/keyboard_layout_english_us_workman_label"
+            android:keyboardLayout="@raw/keyboard_layout_english_us_workman" />
+
     <keyboard-layout android:name="keyboard_layout_german"
             android:label="@string/keyboard_layout_german_label"
             android:keyboardLayout="@raw/keyboard_layout_german" />
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index d18d0f2..4a5907e0 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -82,22 +82,22 @@
     <string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तपाईँले तपाईँको अनलक ढाँचा गलत तरिकाले <xliff:g id="NUMBER_0">%d</xliff:g> पटक खिच्नु भएको छ। \n\n <xliff:g id="NUMBER_1">%d</xliff:g> सेकेन्डमा फेरि कोसिस गर्नुहोस्।"</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="8774056606869646621">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g>पटक।  <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो ट्याब्लेट रिसेट हुनेछ जसले आफ्नो सम्पूर्ण डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="1843331751334128428">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। पछि <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो फोन  रिसेट हुनेछ जसले सम्पूर्ण डेटा मेटाउनेछ।।"</string>
-    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"तपाईं गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। यो ट्याब्लेट रिेसेट गरिनेछ जसले सम्पूर्ण डेटा मेट्नेछ।"</string>
+    <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="258925501999698032">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। यो ट्याब्लेट रिेसेट गरिनेछ जसले सम्पूर्ण डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="7154028908459817066">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। यो फोन रिसेट गरिनेछ जसले सम्पूर्ण डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_erase_user" product="tablet" msgid="6159955099372112688">"तपाईंले गलत तरिकाले  ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g> पटक।  <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_erase_user" product="default" msgid="6945823186629369880">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, यो प्रयोगकर्ता हटाइनेछ जसले  सबै प्रयोगकर्ता डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_now_erasing_user" product="tablet" msgid="3963486905355778734">"तपाईंले गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ ।"</string>
     <string name="kg_failed_attempts_now_erasing_user" product="default" msgid="7729009752252111673">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। यो प्रयोगकर्ता हटाइनेछ जसले सम्पूर्ण प्रयोगकर्ता डेटा मेट्नेछ।"</string>
-    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"तपाईं गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
+    <string name="kg_failed_attempts_almost_at_erase_profile" product="tablet" msgid="4621778507387853694">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि, काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_erase_profile" product="default" msgid="6853071165802933545">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER_0">%d</xliff:g> पटक। <xliff:g id="NUMBER_1">%d</xliff:g> थप असफल प्रयासहरूपछि , काम प्रोफाइल हटाइनेछ जसले सबै प्रोफाइल डेटा मेट्नेछ।"</string>
-    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"तपाईं गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण  प्रोफाइल डेटा मेट्नेछ ।"</string>
+    <string name="kg_failed_attempts_now_erasing_profile" product="tablet" msgid="4686386497449912146">"तपाईँ गलत तरिकाले ट्याब्लेट अनलक गर्ने प्रयास गर्नु भएको छ<xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण  प्रोफाइल डेटा मेट्नेछ ।"</string>
     <string name="kg_failed_attempts_now_erasing_profile" product="default" msgid="4951507352869831265">"तपाईंले गलत तरिकाले फोन अनलक गर्ने प्रयास गर्नु भएको छ <xliff:g id="NUMBER">%d</xliff:g> पटक। काम प्रोफाइल हटाइनेछ जसले सम्पूर्ण प्रोफाइल डेटा मेट्नेछ।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"तपाईंले गलत तरिकाले आफ्नो अनलक ढाँचा <xliff:g id="NUMBER_0">%d</xliff:g> पटक कोर्नुभयो। <xliff:g id="NUMBER_1">%d</xliff:g> विफल प्रयत्नहरू पछि, तपाईंलाई आफ्नो ट्याब्लेट इमेल खाता प्रयोग गरेर अनलक गर्न सोधिने छ।\n\n फेरि प्रयास गर्नुहोस् <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डहरूमा।"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
     <string name="kg_password_wrong_pin_code_pukked" msgid="30531039455764924">"SIM PIN कोड गलत छ। अब तपाईंले अाफ्नो उपकरण खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्दर।"</string>
     <plurals name="kg_password_wrong_pin_code" formatted="false" msgid="6721575017538162249">
-      <item quantity="other"> गलत SIM PIN कोड, तपाईं सँग <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
-      <item quantity="one">SIM PIN कोड गलत छ, तपाईंले अाफ्नो यन्त्र खोल्नलाई तपाईंको वाहकसँग सम्पर्क गर्नै पर्न अघि तपाईंसँग <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+      <item quantity="other"> गलत SIM PIN कोड, तपाईँ सँग <xliff:g id="NUMBER_1">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
+      <item quantity="one">SIM PIN कोड गलत छ, तपाईँले अाफ्नो यन्त्र खोल्नलाई तपाईँको वाहकसँग सम्पर्क गर्नै पर्न अघि तपाईँसँग <xliff:g id="NUMBER_0">%d</xliff:g> पटक प्रयास बाँकी छ।</item>
     </plurals>
     <string name="kg_password_wrong_puk_code_dead" msgid="7077536808291316208">"SIM प्रयोग बिहिन छ। तपाईंको वाहकलाई सम्पर्क गर्नुहोस्।"</string>
     <plurals name="kg_password_wrong_puk_code" formatted="false" msgid="7576227366999858780">
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
index 9e874bd..844b216 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -24,6 +24,9 @@
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 
+/**
+ * TODO Remove this class after we switch to use MtpDatabase.
+ */
 final class CursorHelper {
     static final int DUMMY_HANDLE_FOR_ROOT = 0;
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
new file mode 100644
index 0000000..0534313
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * Database for MTP objects.
+ * The object handle which is identifier for object in MTP protocol is not stable over sessions.
+ * When we resume the process, we need to remap our document ID with MTP's object handle.
+ *
+ * If the remote MTP device is backed by typical file system, the file name
+ * is unique among files in a directory. However, MTP protocol itself does
+ * not guarantee the uniqueness of name so we cannot use fullpath as ID.
+ *
+ * Instead of fullpath, we use artificial ID generated by MtpDatabase itself. The database object
+ * remembers the map of document ID and object handle, and remaps new object handle with document ID
+ * by comparing the directory structure and object name.
+ *
+ * TODO: Remove @VisibleForTesting annotation when we start to use this class.
+ * TODO: Improve performance by SQL optimization.
+ */
+@VisibleForTesting
+class MtpDatabase {
+    private static final int VERSION = 1;
+    private static final String NAME = "mtp";
+
+    private static final String TABLE_DOCUMENTS = "Documents";
+
+    static final String COLUMN_DEVICE_ID = "device_id";
+    static final String COLUMN_STORAGE_ID = "storage_id";
+    static final String COLUMN_OBJECT_HANDLE = "object_handle";
+    static final String COLUMN_PARENT_DOCUMENT_ID = "parent_document_id";
+    static final String COLUMN_ROW_STATE = "row_state";
+
+    /**
+     * The state represents that the row has a valid object handle.
+     */
+    static final int ROW_STATE_MAPPED = 0;
+
+    /**
+     * The state represents that the object handle was cleared because the MTP session closed.
+     * External application can still fetch the unmapped documents. If the external application
+     * tries to open an unmapped document, the provider resolves the document with new object handle
+     * ahead.
+     */
+    static final int ROW_STATE_UNMAPPED = 1;
+
+    /**
+     * The state represents the raw has a valid object handle but it may be going to be merged into
+     * another unmapped row. After fetching all documents under the parent, the database tries to
+     * map the mapping document and the unmapped document in order to keep old document ID alive.
+     */
+    static final int ROW_STATE_MAPPING = 2;
+
+    private static final String SELECTION_DOCUMENT_ID =
+            DocumentsContract.Document.COLUMN_DOCUMENT_ID + " = ?";
+    private static final String SELECTION_ROOT_DOCUMENTS =
+            COLUMN_DEVICE_ID + " = ? AND " + COLUMN_PARENT_DOCUMENT_ID + " IS NULL";
+    private static final String SELECTION_ROOT_DOCUMENTS_WITH_STATE =
+            SELECTION_ROOT_DOCUMENTS + " AND " + COLUMN_ROW_STATE + " = ?";
+
+    static class ParentNotFoundException extends Exception {}
+
+    private static class OpenHelper extends SQLiteOpenHelper {
+        private static final String QUERY_CREATE_DOCUMENTS =
+                "CREATE TABLE " + TABLE_DOCUMENTS + " (" +
+                DocumentsContract.Document.COLUMN_DOCUMENT_ID +
+                    " INTEGER PRIMARY KEY AUTOINCREMENT," +
+                COLUMN_DEVICE_ID + " INTEGER NOT NULL," +
+                COLUMN_STORAGE_ID + " INTEGER," +
+                COLUMN_OBJECT_HANDLE + " INTEGER," +
+                COLUMN_PARENT_DOCUMENT_ID + " INTEGER," +
+                COLUMN_ROW_STATE + " INTEGER NOT NULL," +
+                DocumentsContract.Document.COLUMN_MIME_TYPE + " TEXT," +
+                DocumentsContract.Document.COLUMN_DISPLAY_NAME + " TEXT NOT NULL," +
+                DocumentsContract.Document.COLUMN_SUMMARY + " TEXT," +
+                DocumentsContract.Document.COLUMN_LAST_MODIFIED + " INTEGER," +
+                DocumentsContract.Document.COLUMN_ICON + " INTEGER," +
+                DocumentsContract.Document.COLUMN_FLAGS + " INTEGER NOT NULL," +
+                DocumentsContract.Document.COLUMN_SIZE + " INTEGER NOT NULL);";
+
+        public OpenHelper(Context context) {
+            super(context, NAME, null, VERSION);
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL(QUERY_CREATE_DOCUMENTS);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    private final SQLiteDatabase database;
+
+    @VisibleForTesting
+    MtpDatabase(Context context) {
+        final OpenHelper helper = new OpenHelper(context);
+        database = helper.getWritableDatabase();
+    }
+
+    @VisibleForTesting
+    static void deleteDatabase(Context context) {
+        SQLiteDatabase.deleteDatabase(context.getDatabasePath(NAME));
+    }
+
+    @VisibleForTesting
+    Cursor queryChildDocuments(String[] columnNames) {
+        return database.query(
+                TABLE_DOCUMENTS,
+                columnNames,
+                COLUMN_ROW_STATE + " IN (?, ?)",
+                strings(ROW_STATE_MAPPED, ROW_STATE_UNMAPPED),
+                null,
+                null,
+                null);
+    }
+
+    @VisibleForTesting
+    Cursor queryChildDocuments(String[] columnNames, String parentDocumentId) {
+        return database.query(
+                TABLE_DOCUMENTS,
+                columnNames,
+                COLUMN_ROW_STATE + " IN (?, ?) AND " + COLUMN_PARENT_DOCUMENT_ID + " = ?",
+                strings(ROW_STATE_MAPPED, ROW_STATE_UNMAPPED, parentDocumentId),
+                null,
+                null,
+                null);
+    }
+
+    /**
+     * Puts the roots into the database.
+     * If the database found another unmapped document that shares the same name with the root,
+     * the document may be merged into the unmapped document. In that case, the database marks the
+     * root as 'mapping' and wait for {@link #resolveRootDocuments(int)} is invoked.
+     * @param deviceId Device ID of roots.
+     * @param resources Resources used to get localized root name.
+     * @param roots Roots added to the database.
+     */
+    @VisibleForTesting
+    void putRootDocuments(int deviceId, Resources resources, MtpRoot[] roots) {
+        database.beginTransaction();
+        try {
+            // Add roots to database.
+            final ContentValues values = new ContentValues();
+            for (int i = 0; i < roots.length; i++) {
+                getRootDocumentValues(values, resources, roots[i]);
+                final String displayName =
+                        values.getAsString(DocumentsContract.Document.COLUMN_DISPLAY_NAME);
+                final long numUnmapped = DatabaseUtils.queryNumEntries(
+                        database,
+                        TABLE_DOCUMENTS,
+                        SELECTION_ROOT_DOCUMENTS_WITH_STATE + " AND " +
+                        DocumentsContract.Document.COLUMN_DISPLAY_NAME + " = ?",
+                        strings(deviceId, ROW_STATE_UNMAPPED, displayName));
+                if (numUnmapped != 0) {
+                    values.put(COLUMN_ROW_STATE, ROW_STATE_MAPPING);
+                }
+                database.insert(TABLE_DOCUMENTS, null, values);
+            }
+            database.setTransactionSuccessful();
+        } finally {
+            database.endTransaction();
+        }
+    }
+
+    @VisibleForTesting
+    void putDocument(int deviceId, MtpObjectInfo info) throws Exception {
+        database.beginTransaction();
+        try {
+            final String mimeType = CursorHelper.formatTypeToMimeType(info.getFormat());
+
+            int flag = 0;
+            if (info.getProtectionStatus() == 0) {
+                flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                        DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+                if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
+                    flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
+                }
+            }
+            if (info.getThumbCompressedSize() > 0) {
+                flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+            }
+
+            final ContentValues values = new ContentValues();
+            values.put(COLUMN_DEVICE_ID, deviceId);
+            values.put(COLUMN_STORAGE_ID, info.getStorageId());
+            values.put(COLUMN_OBJECT_HANDLE, info.getObjectHandle());
+            // TODO: Specify correct document ID.
+            values.putNull(COLUMN_PARENT_DOCUMENT_ID);
+            values.put(COLUMN_ROW_STATE, ROW_STATE_MAPPED);
+            values.put(Document.COLUMN_MIME_TYPE, mimeType);
+            values.put(Document.COLUMN_DISPLAY_NAME, info.getName());
+            values.putNull(Document.COLUMN_SUMMARY);
+            values.put(
+                    Document.COLUMN_LAST_MODIFIED,
+                    info.getDateModified() != 0 ? info.getDateModified() : null);
+            values.putNull(Document.COLUMN_ICON);
+            values.put(Document.COLUMN_FLAGS, flag);
+            values.put(Document.COLUMN_SIZE, info.getCompressedSize());
+            if (database.insert(TABLE_DOCUMENTS, null, values) == -1) {
+                throw new Exception("Failed to add document.");
+            }
+
+            database.setTransactionSuccessful();
+        } finally {
+            database.endTransaction();
+        }
+    }
+
+    /**
+     * Clears MTP related identifier.
+     * It clears MTP's object handle and storage ID that are not stable over MTP sessions and mark
+     * the all documents as 'unmapped'. It also remove 'mapping' rows as mapping is cancelled now.
+     */
+    @VisibleForTesting
+    void clearMapping() {
+        database.beginTransaction();
+        try {
+            database.delete(
+                    TABLE_DOCUMENTS, COLUMN_ROW_STATE + " = ?", strings(ROW_STATE_MAPPING));
+            final ContentValues values = new ContentValues();
+            values.putNull(COLUMN_OBJECT_HANDLE);
+            values.putNull(COLUMN_STORAGE_ID);
+            values.put(COLUMN_ROW_STATE, ROW_STATE_UNMAPPED);
+            database.update(TABLE_DOCUMENTS, values, null, null);
+            database.setTransactionSuccessful();
+        } finally {
+            database.endTransaction();
+        }
+    }
+
+    /**
+     * Maps 'unmapped' document and 'mapping' document that don't have document but shares the same
+     * name.
+     * If the database does not find corresponding 'mapping' document, it just removes 'unmapped'
+     * document from the database.
+     * @param deviceId Device ID of roots which the method tries to resolve.
+     */
+    @VisibleForTesting
+    void resolveRootDocuments(int deviceId) {
+        database.beginTransaction();
+        try {
+            // Get 1-to-1 mapping of unmapped document and mapping document.
+            final String unmappedIdQuery = createStateFilter(
+                    ROW_STATE_UNMAPPED, DocumentsContract.Document.COLUMN_DOCUMENT_ID);
+            final String mappingIdQuery = createStateFilter(
+                    ROW_STATE_MAPPING, DocumentsContract.Document.COLUMN_DOCUMENT_ID);
+            // SQL should be like:
+            // SELECT group_concat(CASE WHEN raw_state = 1 THEN document_id ELSE NULL END),
+            //        group_concat(CASE WHEN raw_state = 2 THEN document_id ELSE NULL END)
+            // WHERE device_id = ? AND parent_document_id IS NULL
+            // GROUP BY display_name
+            // HAVING count(CASE WHEN raw_state = 1 THEN document_id ELSE NULL END) = 1 AND
+            //        count(CASE WHEN raw_state = 2 THEN document_id ELSE NULL END) = 1
+            final Cursor mergingCursor = database.query(
+                    TABLE_DOCUMENTS,
+                    new String[] {
+                            "group_concat(" + unmappedIdQuery + ")",
+                            "group_concat(" + mappingIdQuery + ")"
+                    },
+                    SELECTION_ROOT_DOCUMENTS,
+                    strings(deviceId),
+                    DocumentsContract.Document.COLUMN_DISPLAY_NAME,
+                    "count(" + unmappedIdQuery + ") = 1 AND count(" + mappingIdQuery + ") = 1",
+                    null);
+
+            final ContentValues values = new ContentValues();
+            while (mergingCursor.moveToNext()) {
+                final String unmappedId = mergingCursor.getString(0);
+                final String mappingId = mergingCursor.getString(1);
+
+                // Obtain the new values including the latest object handle from mapping row.
+                final Cursor mappingCursor = database.query(
+                        TABLE_DOCUMENTS,
+                        null,
+                        SELECTION_DOCUMENT_ID,
+                        new String[] { mappingId },
+                        null,
+                        null,
+                        null);
+                mappingCursor.moveToNext();
+                values.clear();
+                DatabaseUtils.cursorRowToContentValues(mappingCursor, values);
+                mappingCursor.close();
+                values.remove(DocumentsContract.Document.COLUMN_DOCUMENT_ID);
+
+                // Set the new values into unmapped documents and get it back to 'normal' state.
+                values.put(COLUMN_ROW_STATE, ROW_STATE_MAPPED);
+                database.update(
+                        TABLE_DOCUMENTS,
+                        values,
+                        SELECTION_DOCUMENT_ID,
+                        new String[] { unmappedId });
+
+                // Delete 'mapping' row.
+                database.delete(
+                        TABLE_DOCUMENTS,
+                        SELECTION_DOCUMENT_ID,
+                        new String[] { mappingId });
+            }
+            mergingCursor.close();
+
+            // Delete all unmapped rows that cannot be mapped.
+            database.delete(
+                    TABLE_DOCUMENTS,
+                    SELECTION_ROOT_DOCUMENTS_WITH_STATE,
+                    strings(deviceId, ROW_STATE_UNMAPPED));
+
+            // The database cannot find old document ID for the mapping rows.
+            // Turn the all mapping rows into mapped state, which means the rows become to be
+            // valid with new document ID.
+            values.clear();
+            values.put(COLUMN_ROW_STATE, ROW_STATE_MAPPED);
+            database.update(
+                    TABLE_DOCUMENTS,
+                    values,
+                    SELECTION_ROOT_DOCUMENTS_WITH_STATE,
+                    strings(deviceId, ROW_STATE_MAPPING));
+            database.setTransactionSuccessful();
+        } finally {
+            database.endTransaction();
+        }
+    }
+
+    /**
+     * Gets {@link ContentValues} for the given root.
+     * @param values {@link ContentValues} that receives values.
+     * @param resources Resources used to get localized root name.
+     * @param root Root to be converted {@link ContentValues}.
+     */
+    private static void getRootDocumentValues(
+            ContentValues values, Resources resources, MtpRoot root) {
+        values.clear();
+        values.put(COLUMN_DEVICE_ID, root.mDeviceId);
+        values.put(COLUMN_STORAGE_ID, root.mStorageId);
+        values.putNull(COLUMN_OBJECT_HANDLE);
+        values.putNull(COLUMN_PARENT_DOCUMENT_ID);
+        values.put(COLUMN_ROW_STATE, ROW_STATE_MAPPED);
+        values.put(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+        values.put(Document.COLUMN_DISPLAY_NAME, root.getRootName(resources));
+        values.putNull(Document.COLUMN_SUMMARY);
+        values.putNull(Document.COLUMN_LAST_MODIFIED);
+        values.putNull(Document.COLUMN_ICON);
+        values.put(Document.COLUMN_FLAGS, 0);
+        values.put(Document.COLUMN_SIZE,
+                (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+    }
+
+    /**
+     * Converts values into string array.
+     * @param args Values converted into string array.
+     * @return String array.
+     */
+    private static String[] strings(Object... args) {
+        final String[] results = new String[args.length];
+        for (int i = 0; i < args.length; i++) {
+            results[i] = Objects.toString(args[i]);
+        }
+        return results;
+    }
+
+    /**
+     * Gets SQL expression that represents the given value or NULL depends on the row state.
+     * @param state Expected row state.
+     * @param a SQL value.
+     * @return Expression that represents a if the row state is expected one, and represents NULL
+     *     otherwise.
+     */
+    private static String createStateFilter(int state, String a) {
+        return "CASE WHEN " + COLUMN_ROW_STATE + " = " + Integer.toString(state) +
+                " THEN " + a + " ELSE NULL END";
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
new file mode 100644
index 0000000..e7d8481
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.database.Cursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+@SmallTest
+public class MtpDatabaseTest extends AndroidTestCase {
+    private final String[] COLUMN_NAMES = new String[] {
+        DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+        MtpDatabase.COLUMN_DEVICE_ID,
+        MtpDatabase.COLUMN_STORAGE_ID,
+        MtpDatabase.COLUMN_OBJECT_HANDLE,
+        DocumentsContract.Document.COLUMN_MIME_TYPE,
+        DocumentsContract.Document.COLUMN_DISPLAY_NAME,
+        DocumentsContract.Document.COLUMN_SUMMARY,
+        DocumentsContract.Document.COLUMN_LAST_MODIFIED,
+        DocumentsContract.Document.COLUMN_ICON,
+        DocumentsContract.Document.COLUMN_FLAGS,
+        DocumentsContract.Document.COLUMN_SIZE
+    };
+
+    private final TestResources resources = new TestResources();
+
+    @Override
+    public void tearDown() {
+        MtpDatabase.deleteDatabase(getContext());
+    }
+
+    public void testPutRootDocument() throws Exception {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 1, "Device", "Storage", 1000, 2000, ""),
+                new MtpRoot(0, 2, "Device", "Storage", 1000, 2000, ""),
+                new MtpRoot(0, 3, "Device", "/@#%&<>Storage", 1000, 2000,"")
+        });
+
+        final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES);
+        assertEquals(3, cursor.getCount());
+
+        cursor.moveToNext();
+        assertEquals("documentId", 1, cursor.getInt(0));
+        assertEquals("deviceId", 0, cursor.getInt(1));
+        assertEquals("storageId", 1, cursor.getInt(2));
+        assertTrue("objectHandle", cursor.isNull(3));
+        assertEquals("mimeType", DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(4));
+        assertEquals("displayName", "Device Storage", cursor.getString(5));
+        assertTrue("summary", cursor.isNull(6));
+        assertTrue("lastModified", cursor.isNull(7));
+        assertTrue("icon", cursor.isNull(8));
+        assertEquals("flag", 0, cursor.getInt(9));
+        assertEquals("size", 1000, cursor.getInt(10));
+
+        cursor.moveToNext();
+        assertEquals("documentId", 2, cursor.getInt(0));
+        assertEquals("displayName", "Device Storage", cursor.getString(5));
+
+        cursor.moveToNext();
+        assertEquals("documentId", 3, cursor.getInt(0));
+        assertEquals("displayName", "Device /@#%&<>Storage", cursor.getString(5));
+
+        cursor.close();
+    }
+
+    public void testPutDocument() throws Exception {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        final MtpObjectInfo.Builder builder = new MtpObjectInfo.Builder();
+        builder.setObjectHandle(100);
+        builder.setName("test.txt");
+        builder.setStorageId(5);
+        builder.setFormat(MtpConstants.FORMAT_TEXT);
+        builder.setCompressedSize(1000);
+        database.putDocument(0, builder.build());
+
+        final Cursor cursor = database.queryChildDocuments(COLUMN_NAMES);
+        assertEquals(1, cursor.getCount());
+        cursor.moveToNext();
+        assertEquals("documentId", 1, cursor.getInt(0));
+        assertEquals("deviceId", 0, cursor.getInt(1));
+        assertEquals("storageId", 5, cursor.getInt(2));
+        assertEquals("objectHandle", 100, cursor.getInt(3));
+        assertEquals("mimeType", "text/plain", cursor.getString(4));
+        assertEquals("displayName", "test.txt", cursor.getString(5));
+        assertTrue("summary", cursor.isNull(6));
+        assertTrue("lastModified", cursor.isNull(7));
+        assertTrue("icon", cursor.isNull(8));
+        assertEquals(
+                "flag",
+                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                DocumentsContract.Document.FLAG_SUPPORTS_WRITE,
+                cursor.getInt(9));
+        assertEquals("size", 1000, cursor.getInt(10));
+    }
+
+    public void testRestoreIdForRootDocuments() throws Exception {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        final String[] columns = new String[] {
+                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+                MtpDatabase.COLUMN_STORAGE_ID,
+                DocumentsContract.Document.COLUMN_DISPLAY_NAME
+        };
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage A", 0, 0, ""),
+                new MtpRoot(0, 101, "Device", "Storage B", 0, 0, "")
+        });
+
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertEquals("storageId", 100, cursor.getInt(1));
+            assertEquals("name", "Device Storage A", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertEquals("storageId", 101, cursor.getInt(1));
+            assertEquals("name", "Device Storage B", cursor.getString(2));
+            cursor.close();
+        }
+
+        database.clearMapping();
+
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertTrue("storageId", cursor.isNull(1));
+            assertEquals("name", "Device Storage A", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertTrue("storageId", cursor.isNull(1));
+            assertEquals("name", "Device Storage B", cursor.getString(2));
+            cursor.close();
+        }
+
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 200, "Device", "Storage A", 0, 0, ""),
+                new MtpRoot(0, 202, "Device", "Storage C", 0, 0, "")
+        });
+
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(3, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertTrue("storageId", cursor.isNull(1));
+            assertEquals("name", "Device Storage A", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertTrue("storageId", cursor.isNull(1));
+            assertEquals("name", "Device Storage B", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 4, cursor.getInt(0));
+            assertEquals("storageId", 202, cursor.getInt(1));
+            assertEquals("name", "Device Storage C", cursor.getString(2));
+            cursor.close();
+        }
+
+        database.resolveRootDocuments(0);
+
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertEquals("storageId", 200, cursor.getInt(1));
+            assertEquals("name", "Device Storage A", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 4, cursor.getInt(0));
+            assertEquals("storageId", 202, cursor.getInt(1));
+            assertEquals("name", "Device Storage C", cursor.getString(2));
+            cursor.close();
+        }
+    }
+
+    public void testRestoreIdForDifferentDevices() throws Exception {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        final String[] columns = new String[] {
+                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+                MtpDatabase.COLUMN_STORAGE_ID,
+                DocumentsContract.Document.COLUMN_DISPLAY_NAME
+        };
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage", 0, 0, "")
+        });
+        database.putRootDocuments(1, resources, new MtpRoot[] {
+                new MtpRoot(1, 100, "Device", "Storage", 0, 0, "")
+        });
+
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertEquals("storageId", 100, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertEquals("storageId", 100, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.close();
+        }
+
+        database.clearMapping();
+
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 200, "Device", "Storage", 0, 0, "")
+        });
+        database.putRootDocuments(1, resources, new MtpRoot[] {
+                new MtpRoot(1, 300, "Device", "Storage", 0, 0, "")
+        });
+        database.resolveRootDocuments(0);
+        database.resolveRootDocuments(1);
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertEquals("storageId", 200, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertEquals("storageId", 300, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.close();
+        }
+    }
+
+    public void testClearMtpIdentifierBeforeResolveRootDocuments() {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        final String[] columns = new String[] {
+                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+                MtpDatabase.COLUMN_STORAGE_ID,
+                DocumentsContract.Document.COLUMN_DISPLAY_NAME
+        };
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
+        });
+        database.clearMapping();
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 200, "Device", "Storage", 0, 0, ""),
+        });
+        database.clearMapping();
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 300, "Device", "Storage", 0, 0, ""),
+        });
+        database.resolveRootDocuments(0);
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(1, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 1, cursor.getInt(0));
+            assertEquals("storageId", 300, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.close();
+        }
+    }
+
+    public void testPutSameNameRootsAfterClearing() throws Exception {
+        final MtpDatabase database = new MtpDatabase(getContext());
+        final String[] columns = new String[] {
+                DocumentsContract.Document.COLUMN_DOCUMENT_ID,
+                MtpDatabase.COLUMN_STORAGE_ID,
+                DocumentsContract.Document.COLUMN_DISPLAY_NAME
+        };
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 100, "Device", "Storage", 0, 0, ""),
+        });
+        database.clearMapping();
+        database.putRootDocuments(0, resources, new MtpRoot[] {
+                new MtpRoot(0, 200, "Device", "Storage", 0, 0, ""),
+                new MtpRoot(0, 201, "Device", "Storage", 0, 0, ""),
+        });
+        database.resolveRootDocuments(0);
+        {
+            final Cursor cursor = database.queryChildDocuments(columns);
+            assertEquals(2, cursor.getCount());
+            cursor.moveToNext();
+            assertEquals("documentId", 2, cursor.getInt(0));
+            assertEquals("storageId", 200, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.moveToNext();
+            assertEquals("documentId", 3, cursor.getInt(0));
+            assertEquals("storageId", 201, cursor.getInt(1));
+            assertEquals("name", "Device Storage", cursor.getString(2));
+            cursor.close();
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 0c03814c..5765f0a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -16,9 +16,6 @@
 
 package com.android.mtp;
 
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
 import android.database.Cursor;
 import android.mtp.MtpConstants;
 import android.mtp.MtpObjectInfo;
@@ -26,7 +23,6 @@
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
-import android.test.mock.MockResources;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.FileNotFoundException;
@@ -39,16 +35,7 @@
     private TestContentResolver mResolver;
     private MtpDocumentsProvider mProvider;
     private TestMtpManager mMtpManager;
-    private final MockResources mResources = new MockResources() {
-        @Override
-        public String getString(int id) throws NotFoundException {
-            switch (id) {
-                case R.string.root_name:
-                    return "%1$s %2$s";
-            }
-            throw new NotFoundException();
-        }
-    };
+    private final TestResources mResources = new TestResources();
 
     @Override
     public void setUp() throws IOException {
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
new file mode 100644
index 0000000..eb80e3b
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResources.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.test.mock.MockResources;
+
+class TestResources extends MockResources {
+    @Override
+    public String getString(int id) throws NotFoundException {
+        switch (id) {
+            case R.string.root_name:
+                return "%1$s %2$s";
+        }
+        throw new NotFoundException();
+    }
+}
diff --git a/packages/SettingsLib/res/values-af/arrays.xml b/packages/SettingsLib/res/values-af/arrays.xml
new file mode 100644
index 0000000..6693997
--- /dev/null
+++ b/packages/SettingsLib/res/values-af/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skandeer tans…"</item>
+    <item msgid="8513729475867537913">"Koppel tans…"</item>
+    <item msgid="515055375277271756">"Staaf tans…"</item>
+    <item msgid="1943354004029184381">"Bekom tans IP-adres…"</item>
+    <item msgid="4221763391123233270">"Gekoppel"</item>
+    <item msgid="624838831631122137">"Opgeskort"</item>
+    <item msgid="7979680559596111948">"Ontkoppel tans…"</item>
+    <item msgid="1634960474403853625">"Ontkoppel"</item>
+    <item msgid="746097431216080650">"Onsuksesvol"</item>
+    <item msgid="6367044185730295334">"Geblokkeer"</item>
+    <item msgid="503942654197908005">"Vermy tydelik swak verbinding"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skandeer tans…"</item>
+    <item msgid="355508996603873860">"Koppel tans aan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Staaf tans met <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Verkry tans IP-adres van <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Gekoppel aan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Opgeskort"</item>
+    <item msgid="7698638434317271902">"Ontkoppel tans van <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Ontkoppel"</item>
+    <item msgid="8578370891960825148">"Onsuksesvol"</item>
+    <item msgid="5660739516542454527">"Geblokkeer"</item>
+    <item msgid="1805837518286731242">"Vermy tydelik swak verbinding"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
new file mode 100644
index 0000000..73c82fd
--- /dev/null
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan nie skandeer vir netwerke nie"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Geen"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Gestoor"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Gedeaktiveer"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-opstelling het misluk"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-verbinding het misluk"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Stawingsprobleem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Nie binne ontvangs nie"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang bespeur nie, sal nie outomaties herkoppel nie."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Gestoor deur <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Gekoppel via Wi-Fi-assistent"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Gekoppel via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Beskikbaar via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Gekoppel, geen internet nie"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ontkoppel"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ontkoppel tans…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Verbind tans…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Gekoppel"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Verbind tans…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Gekoppel (geen foon nie)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Gekoppel (geen media nie)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Gekoppel (geen boodskaptoegang nie)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Gekoppel (geen foon of media nie)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-oudio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Foonoudio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Lêeroordrag"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Invoertoestel"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internettoegang"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontakdeling"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Gebruik vir kontakdeling"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling van internetverbinding"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Boodskaptoegang"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-toegang"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Gekoppel aan media-oudio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Gekoppel aan foonoudio"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Gekoppel aan lêeroordragbediener"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Gekoppel aan kaart"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Aan SAP gekoppel"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nie gekoppel aan lêeroordragbediener nie"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Gekoppel aan invoertoestel"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Aan toestel gekoppel vir internettoegang"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deel plaaslike internetverbinding met toestel"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gebruik vir internettoegang"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gebruik vir kaart"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gebruik vir SIM-toegang"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gebruik vir media-oudio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gebruik vir foonoudio"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gebruik vir lêeroordrag"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gebruik vir invoer"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Bind saam"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"BIND SAAM"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Kanselleer"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Saambinding bied toegang tot jou kontakte en oproepgeskiedenis wanneer dit gekoppel is."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kon nie saambind met <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nie."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kon nie met <xliff:g id="DEVICE_NAME">%1$s</xliff:g> saambind nie weens \'n verkeerde PIN of wagwoordsleutel."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan nie met <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kommunikeer nie."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Saambinding verwerp deur <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi af."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi is ontkoppel."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi een staaf."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi twee stawe."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi drie stawe."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi-sein vol."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android-bedryfstelsel"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Verwyderde programme"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Verwyderde programme en gebruikers"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-verbinding"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Wi-Fi-warmkol"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-verbinding"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Verbinding"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"USB-verbinding en Wi-Fi-warmkol"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Werkprofiel"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gas"</string>
+    <string name="unknown" msgid="1592123443519355854">"Onbekend"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Gebruiker: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Sommige verstekke gestel"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Geen verstekke gestel nie"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-am/arrays.xml b/packages/SettingsLib/res/values-am/arrays.xml
new file mode 100644
index 0000000..46790d6
--- /dev/null
+++ b/packages/SettingsLib/res/values-am/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"በማገናኘት ላይ…"</item>
+    <item msgid="515055375277271756">"በማረጋገጥ ላይ...."</item>
+    <item msgid="1943354004029184381">"የIP አድራሻ በማግኘት ላይ..."</item>
+    <item msgid="4221763391123233270">"ተገናኝቷል"</item>
+    <item msgid="624838831631122137">"ታግዷል"</item>
+    <item msgid="7979680559596111948">"በማለያየት ላይ...."</item>
+    <item msgid="1634960474403853625">"ተለያየ"</item>
+    <item msgid="746097431216080650">"አልተሳካም"</item>
+    <item msgid="6367044185730295334">"ታግዷል"</item>
+    <item msgid="503942654197908005">"ለጊዜያዊነት ከደካማ ግኑኝነት በመታቀብ ላይ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"ለ<xliff:g id="NETWORK_NAME">%1$s</xliff:g> የተገናኘ"</item>
+    <item msgid="1330262655415760617">"ታግዷል"</item>
+    <item msgid="7698638434317271902">"ከ<xliff:g id="NETWORK_NAME">%1$s</xliff:g> በማለያየት ላይ...."</item>
+    <item msgid="197508606402264311">"ተለያየ"</item>
+    <item msgid="8578370891960825148">"አልተሳካም"</item>
+    <item msgid="5660739516542454527">"ታግዷል"</item>
+    <item msgid="1805837518286731242">"ለጊዜያዊነት ከደካማ ግኑኝነት በመታቀብ ላይ"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
new file mode 100644
index 0000000..4e94d87
--- /dev/null
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ለአውታረመረቦች መቃኘት አይቻልም"</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_network_failure" msgid="2364951338436007124">"የአይ.ፒ. ውቅረት መሰናከል"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"የWiFi ግንኙነት መሰናከል"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"የማረጋገጫ ችግር"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"በክልል ውስጥ የለም"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ምንም የበይነ መረብ መዳረሻ ተፈልጎ አልተገኘም፣ በራስ-ሰር እንደገና እንዲገናኝ አይደረግም።"</string>
+    <string name="saved_network" msgid="4352716707126620811">"የተቀመጠው በ<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"በWi‑Fi ረዳት አማካኝነት ተገናኝቷል"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"በ%1$s በኩል መገናኘት"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"በ%1$s በኩል የሚገኝ"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ተለያይቷል"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"በመለያየት ላይ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"በማገናኘት ላይ…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"ተገናኝቷል"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"በማገናኘት ላይ..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"ተያይዟል (ምንም ስልክ የለም)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ተያይዟል (ምንም ማህደረ መረጃ የለም)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ተገናኝቷል (ምንም የመልዕክት መዳረሻ የለም)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ተያይዟል (ምንም ስልክ ወይም ማህደረ መረጃ የለም)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"የማህደረ መረጃ ኦዲዮ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"የስልክ ኦዲዮ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ፋይል ማስተላለፍ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ግቤት መሣሪያ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"የበይነመረብ ድረስ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"እውቂያ ማጋራት"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"እውቂያን ለማጋራት ተጠቀም"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"የበይነ መረብ ተያያዥ ማጋሪያ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"የመልዕክት መዳረሻ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"የሲም መዳረሻ"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ወደ ማህደረ  መረጃ  አውዲዮ ተያይዟል"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ወደ ስልክ አውዲዮ ተያይዟል"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ወደ ፋይል ዝውውር አገልጋይ ተያይዟል"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ከካርታ ጋር ተገናኝቷል"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"ከSAP ጋር ተገናኝቷል"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ከፋይል ዝውውር አገልጋይ ጋር አልተያያዘም"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ወደ ግቤት መሣሪያ ተያይዟል"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ለበይነመረብ ድረስ ወደ መሣሪያ ተያይዟል"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"የአካባቢያዊ በይነመረብ ተያያዥ ከመሣሪያ ጋር በማጋራት ላይ"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ለበይነ መረብ ድረስ ተጠቀም"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ለካርታ ይጠቀሙ"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ለሲም መዳረሻ መጠቀም"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ለማህደረመረጃ ድምፅተጠቀም"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ለስልክ ድምፅ ተጠቀም"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ለፋይል ዝውውር ተጠቀም"</string>
+    <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_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> ጋር ትክክለኛ ባልሆነ ፒን ወይም የይለፍቁልፍ ምክንያት ማጣመር አልተቻለም::"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ከ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ጋር ግንኙነት መመስረት አልተቻለም።"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ማጣመር በ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ተገፍቷል።"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi ጠፍቷል።"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"የWifi ግንኙነት ተቋርጧል።"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"አንድ የWiFi አሞሌ።"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ሁለት የWiFi አሞሌዎች።"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"ሦስት የWiFi አሞሌዎች።"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"የWiFi ምልክት ሙሉ ነው።"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android  ስርዓተ ክወና"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"የተወገዱ መተግበሪያዎች"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"የተወገዱ መተግበሪያዎች እና ተጠቃሚዎች"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB መሰካት"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ተጓጓዥ ድረስ ነጥቦች"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ብሉቱዝ ማያያዝ"</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="8101244883654409696">"የስራ መገለጫ"</string>
+    <string name="user_guest" msgid="8475274842845401871">"እንግዳ"</string>
+    <string name="unknown" msgid="1592123443519355854">"ያልታወቀ"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"ተጠቃሚ፦ <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ar/arrays.xml b/packages/SettingsLib/res/values-ar/arrays.xml
new file mode 100644
index 0000000..866959f
--- /dev/null
+++ b/packages/SettingsLib/res/values-ar/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"جارٍ الاتصال…"</item>
+    <item msgid="515055375277271756">"جارٍ المصادقة…"</item>
+    <item msgid="1943354004029184381">"‏جارٍ الحصول على عنوان IP…"</item>
+    <item msgid="4221763391123233270">"متصل"</item>
+    <item msgid="624838831631122137">"معلق"</item>
+    <item msgid="7979680559596111948">"جارٍ فصل الاتصال..."</item>
+    <item msgid="1634960474403853625">"غير متصل"</item>
+    <item msgid="746097431216080650">"غير ناجح"</item>
+    <item msgid="6367044185730295334">"تم حظرها"</item>
+    <item msgid="503942654197908005">"يتم تجنب الاتصال الضعيف مؤقتًا"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"‏جارٍ الحصول على عنوان IP من <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"متصل بـ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"معلق"</item>
+    <item msgid="7698638434317271902">"جارٍ قطع الاتصال بـ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"غير متصل"</item>
+    <item msgid="8578370891960825148">"غير ناجح"</item>
+    <item msgid="5660739516542454527">"تم حظرها"</item>
+    <item msgid="1805837518286731242">"يتم تجنب الاتصال الضعيف مؤقتًا"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
new file mode 100644
index 0000000..3710f7b
--- /dev/null
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"لا يمكن فحص الشبكات"</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_network_failure" msgid="2364951338436007124">"‏أخفقت تهيئة عنوان IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏أخفق اتصال WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"حدثت مشكلة في المصادقة"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"ليست في النطاق"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"لم يتم اكتشاف اتصال بالإنترنت."</string>
+    <string name="saved_network" msgid="4352716707126620811">"تم الحفظ بواسطة <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"‏تم التوصيل عبر مساعد Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"‏تم الاتصال عبر %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"‏متوفرة عبر %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"متصلة، ولا يتوفر إنترنت"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"غير متصل"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"جارٍ قطع الاتصال..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"جارٍ الاتصال…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"متصل"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"جارٍ الاقتران..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"متصل (بجهاز غير الهاتف)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"متصل (بجهاز غير الوسائط)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"تم الاتصال (يتعذر الدخول إلى الرسائل)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"متصل (بجهاز غير الهاتف أو الوسائط)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"الإعدادات الصوتية للوسائط"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"الإعدادات الصوتية للهاتف"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"نقل الملف"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"جهاز الإرسال"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"الدخول إلى الإنترنت"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"مشاركة جهة الاتصال"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"استخدام مع مشاركة جهة الاتصال"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"مشاركة اتصال الإنترنت"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"الدخول إلى الرسائل"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"‏الوصول إلى شريحة SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"متصل بالإعدادات الصوتية للوسائط"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"متصل بالإعدادات الصوتية للهاتف"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"متصل بخادم نقل الملف"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"تم الاتصال بملف تعريف الدخول إلى الرسائل"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"‏تم الاتصال بـ SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"غير متصل بخادم نقل الملفات"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"متصل بجهاز الإدخال"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"متصل بالجهاز لدخول الإنترنت"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"مشاركة الاتصال المحلي بالإنترنت مع الجهاز"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"الاستخدام للدخول على الإنترنت"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"استخدام لملف تعريف الدخول إلى الرسائل"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"‏الاستخدام للوصول إلى شريحة SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"الاستخدام للإعدادات الصوتية للوسائط"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"الاستخدام لإعدادات الهاتف الصوتية"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"استخدامه لنقل الملفات"</string>
+    <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_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> نظرًا لوجود رقم تعريف شخصي أو مفتاح مرور غير صحيح."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"لا يمكن الاتصال بـ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"تم رفض الاقتران بواسطة <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"‏تم إيقاف Wi-Fi."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"‏تم قطع اتصال Wi-Fi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"‏إشارة Wi-Fi تتكون من شريط واحد."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"‏إشارة Wi-Fi تتكون من شريطين."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"‏إشارة Wi-Fi تتكون من ثلاثة أشرطة."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"‏إشارة Wi-Fi كاملة."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"‏نظام التشغيل Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"التطبيقات المزالة"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"التطبيقات والمستخدمون الذين تمت إزالتهم"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏ربط USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"نقطة اتصال محمولة"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ربط البلوتوث"</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="8101244883654409696">"الملف الشخصي للعمل"</string>
+    <string name="user_guest" msgid="8475274842845401871">"مدعو"</string>
+    <string name="unknown" msgid="1592123443519355854">"غير معروف"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"المستخدم: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/arrays.xml b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
new file mode 100644
index 0000000..442d155
--- /dev/null
+++ b/packages/SettingsLib/res/values-az-rAZ/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skan edilir ..."</item>
+    <item msgid="8513729475867537913">"Qoşulur ..."</item>
+    <item msgid="515055375277271756">"Autentifikasiya edilir..."</item>
+    <item msgid="1943354004029184381">"IP ünvanı əldə edilir..."</item>
+    <item msgid="4221763391123233270">"Qoşulu"</item>
+    <item msgid="624838831631122137">"Durdurulmuş"</item>
+    <item msgid="7979680559596111948">"Ayrılır ..."</item>
+    <item msgid="1634960474403853625">"Əlaqə kəsildi"</item>
+    <item msgid="746097431216080650">"Uğursuz"</item>
+    <item msgid="6367044185730295334">"Bloklanıb"</item>
+    <item msgid="503942654197908005">"Keyfiyyətsiz bağlantıdan müvəqqəti qaçış"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skan edilir..."</item>
+    <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> qoşulur…"</item>
+    <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ilə autentifikasiya edilir..."</item>
+    <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> şəbəkəsindən IP ünvan əldə olunur..."</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> qoşuldu"</item>
+    <item msgid="1330262655415760617">"Dayandırılıb"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> şəbəkəsindən ayrılır..."</item>
+    <item msgid="197508606402264311">"Bağlantı kəsildi"</item>
+    <item msgid="8578370891960825148">"Uğursuz"</item>
+    <item msgid="5660739516542454527">"Bloklanıb"</item>
+    <item msgid="1805837518286731242">"Zəif bağlantı müvəqqəti aradan qaldırılır"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
new file mode 100644
index 0000000..9f46424
--- /dev/null
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Şəbəkə axtarmaq olmur"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Heç biri"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Yadda saxlanılan"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiv"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Konfiqurasiya Uğursuzluğu"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi Bağlantı Uğursuzluğu"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikasiya problemi"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Diapazonda deyil"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet bağlantısı tapılmadı, avtomatik olaraq yenidən qoşulmayacaq."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tərəfindən saxlandı"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi köməkçisi vasitəsilə qoşulub"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s vasitəsilə qoşuludur"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s vasitəsilə əlçatandır"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Qoşuludur, internet yoxdur"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ayrıldı"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ayrılır..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Qoşulur..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Qoşulu"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Cütləşdirmə"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Qoşulub (telefonsuz)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Qoşuludur (media yoxdur)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Qoşulu (mesaj girişi yoxdur)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Bağlantı yaradılıb (telefon və ya media deyil)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefon audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fayl transferi"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Daxiletmə cihazı"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"İnternet girişi"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontakt paylaşımı"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Kontakt paylaşımı üçün istifadə edin"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"internet bağlantı paylaşımı"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Mesaj Girişi"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Girişi"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Media audioya birləşdirilib"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon audiosuna qoşulu"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fayl transfer serverinə qoşulu"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Xəritəyə qoşulu"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP(es-ey-pi)\'yə qoşuludur"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fayl transfer serverinə qoşulmayıb"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Daxiletmə cihazına qoşuldu"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"İnternet girişi üçün cihaza birləşdi"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokal internet bağlantısı cihazla paylaşılır"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"İnternet girişi üçün istifadə edin"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Xəritə üçün istifadə et"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM girişi üçün istifadə edin"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Media audio istifadə edin"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon audiosu istifadə edin"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Fayl transferi üçün istifadə edin"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Daxiletmə üçün istifadə edin"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Birləşdir"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"CÜTLƏNDİR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ləğv et"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Qoşulan zaman kontaktlarınıza və çağrı tarixçəsinə giriş cütlənməsi."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə birləşdirmək alınmadı."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Yanlış PIN və ya parola görə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə cütləşmək alınmadı."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ilə ünsiyyət qurula bilmir."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Cütləşdirmə <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tərəfindən rədd edildi."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi sönülüdür."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi bağlantı kəsildi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi bir xətdir."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi iki xətdir."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi üç xətdir."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi siqnalı tamdır."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Silinmiş tətbiqlər"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Tətbiqləri və istifadəçiləri silin"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Birləşmə"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portativ hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth birləşmə"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Birləşmə"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Birləşmə və daşınan hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"İş profili"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Qonaq"</string>
+    <string name="unknown" msgid="1592123443519355854">"Naməlum"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"İstifadəçi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Bəzi susmaya görələr təyin edilib"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Susmaya görələr təyin edilməyib."</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
new file mode 100644
index 0000000..a754787
--- /dev/null
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Установява се връзка…"</item>
+    <item msgid="515055375277271756">"Удостоверява се..."</item>
+    <item msgid="1943354004029184381">"Получава се IP адрес"</item>
+    <item msgid="4221763391123233270">"Установена е връзка"</item>
+    <item msgid="624838831631122137">"Прекъсната"</item>
+    <item msgid="7979680559596111948">"Изключва се..."</item>
+    <item msgid="1634960474403853625">"Изкл."</item>
+    <item msgid="746097431216080650">"Неуспешно"</item>
+    <item msgid="6367044185730295334">"Блокирано"</item>
+    <item msgid="503942654197908005">"Временно се избягва лоша връзка"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"IP адресът от <xliff:g id="NETWORK_NAME">%1$s</xliff:g> се получава..."</item>
+    <item msgid="8937994881315223448">"Установена е връзка с/ъс<xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Прекъсната"</item>
+    <item msgid="7698638434317271902">"Изключва се от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Изкл."</item>
+    <item msgid="8578370891960825148">"Неуспешно"</item>
+    <item msgid="5660739516542454527">"Блокирано"</item>
+    <item msgid="1805837518286731242">"Временно се избягва лоша връзка"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
new file mode 100644
index 0000000..5938f14
--- /dev/null
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не може да се сканира за мрежи"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Извън обхват"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е открит достъп до интернет. Няма да се свърже отново автоматично."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Запазено от <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Установена е връзка чрез помощника за Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Установена е връзка през „%1$s“"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Мрежата е достъпна през „%1$s“"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Установена е връзка – няма достъп до интернет"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Изкл."</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Изключва се..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Установява се връзка…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Установена е връзка"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Сдвояване..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Свързано (без телефона)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Свързано (без мултимедията)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Има връзка (няма достъп до съобщенията)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Свързано (без телефона или мултимедията)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Мултимедийно аудио"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Звук на телефона"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Прехвърляне на файл"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Входно устройство"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Достъп до интернет"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Споделяне на контакти"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Използване за споделяне на контакти"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Споделяне на връзката с интернет"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Достъп до съобщенията"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Достъп до SIM картата"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Установена е връзка с медийно аудио"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Връзка със звука на телефона"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Установена е връзка със сървър за трансфер на файлове"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Има връзка с MAP"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Установена е връзка със SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Няма връзка със сървър за трансфер на файлове"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Има връзка с устройството за въвеждане"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Има връзка с у-во за достъп до интернет"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Лок. връзка с интернет се споделя с у-вото"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Използване за достъп до интернет"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Да се използва за MAP"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Използване за достъп до SIM картата"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Употреба за медийно аудио"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Използване на телефон за аудио"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Използване на за пренос на файлове"</string>
+    <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_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> поради неправилен ПИН или код за достъп."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не може да се свърже с/ъс <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Сдвояването е отхвърлено от <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi е изключен."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Няма връзка с Wi-Fi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi е с една чертичка."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi е с две чертички."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi е с три чертички."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Сигналът за Wi-Fi е пълен."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android (ОС)"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Премахнати приложения"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Премахнати приложения и потребители"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Тетъринг през USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносима точка за достъп"</string>
+    <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="8101244883654409696">"Служебен потр. профил"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Гост"</string>
+    <string name="unknown" msgid="1592123443519355854">"Неизвестно"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Потребител: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/arrays.xml b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
new file mode 100644
index 0000000..367e268
--- /dev/null
+++ b/packages/SettingsLib/res/values-bn-rBD/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"সংযুক্ত হচ্ছে..."</item>
+    <item msgid="515055375277271756">"প্রমাণীকরণ হচ্ছে..."</item>
+    <item msgid="1943354004029184381">"IP ঠিকানা প্রাপ্ত করা হচ্ছে..."</item>
+    <item msgid="4221763391123233270">"সংযুক্ত হয়েছে"</item>
+    <item msgid="624838831631122137">"স্থগিত করা হয়েছে"</item>
+    <item msgid="7979680559596111948">"সংযোগ বিচ্ছিন্ন হচ্ছে..."</item>
+    <item msgid="1634960474403853625">"সংযোগ বিচ্ছিন্ন করা হয়েছে"</item>
+    <item msgid="746097431216080650">"অসফল"</item>
+    <item msgid="6367044185730295334">"ব্লক করা"</item>
+    <item msgid="503942654197908005">"সাময়িকরূপে দুর্বল সংযোগ এড়ানো হচ্ছে"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> তে সংযুক্ত হয়েছে"</item>
+    <item msgid="1330262655415760617">"স্থগিত করা হয়েছে"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> থেকে সংযোগ বিচ্ছিন্ন হচ্ছে…"</item>
+    <item msgid="197508606402264311">"সংযোগ বিচ্ছিন্ন করা হয়েছে"</item>
+    <item msgid="8578370891960825148">"অসফল"</item>
+    <item msgid="5660739516542454527">"অবরুদ্ধ"</item>
+    <item msgid="1805837518286731242">"সাময়িকরূপে দুর্বল সংযোগ এড়ানো হচ্ছে"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
new file mode 100644
index 0000000..612f684
--- /dev/null
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"নেটওয়ার্কগুলির জন্য স্ক্যান করা যাবে না"</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_network_failure" msgid="2364951338436007124">"IP কনফিগারেশনের ব্যর্থতা"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi সংযোগের ব্যর্থতা"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"প্রমাণীকরণ সমস্যা"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"পরিসরের মধ্যে নয়"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"কোনো ইন্টারনেট অ্যাক্সেস শনাক্ত হয়নি, স্বয়ংক্রিয়ভাবে পুনরায় সংযোগ স্থাপন করবে না৷"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> দ্বারা সংরক্ষিত"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi সহায়ক-এর মাধ্যমে সংযুক্ত হয়েছে"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s মাধ্যমে সংযুক্ত হয়েছে"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s এর মাধ্যমে উপলব্ধ"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"সংযুক্ত, ইন্টারনেট নেই"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"সংযোগ বিচ্ছিন্ন করা হয়েছে"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"সংযোগ বিচ্ছিন্ন হচ্ছে..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"সংযুক্ত হচ্ছে..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"সংযুক্ত হয়েছে"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"যুক্ত করা হচ্ছে..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"সংযুক্ত (কোনো ফোন নেই)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"সংযুক্ত (কোনো মিডিয়া নেই)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"সংযুক্ত (কোনো বার্তা অ্যাক্সেস নেই)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"সংযুক্ত (কোনো ফোন বা মিডিয়া নেই)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"মিডিয়া অডিও"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ফোন অডিও"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ফাইল স্থানান্তর"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ইনপুট ডিভাইস"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ইন্টারনেট অ্যাক্সেস"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"পরিচিতি ভাগ করা"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"পরিচিতি ভাগ করার কাজে ব্যবহার করুন"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ইন্টারনেট সংযোগ ভাগ করা হচ্ছে"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"বার্তা অ্যাক্সেস"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM -এর অ্যাক্সেস"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"মিডিয়া অডিওতে সংযুক্ত রয়েছে"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ফোন অডিওতে সংযুক্ত"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"মানচিত্রে সংযুক্ত"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP -তে সংযুক্ত হয়েছে"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ফাইল স্থানান্তর সার্ভারের সঙ্গে সংযুক্ত নয়"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ইনপুট ডিভাইসে সংযুক্ত"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ইন্টারনেট অ্যাক্সেসের জন্য ডিভাইসে সংযুক্ত"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ডিভাইসের সাথে স্থানীয় ইন্টারনেট সংযোগ ভাগ করছে"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ইন্টারনেট অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"মানচিত্রের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM -এর অ্যাক্সেসের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"মিডিয়া অডিওয়ের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ফোন অডিওয়ের জন্য ব্যবহার করুন"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ফাইল স্থানান্তরের জন্য ব্যবহার করুন"</string>
+    <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_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> এর সঙ্গে যুক্ত করা যায়নি।"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> এর সঙ্গে যোগাযোগ করতে পারবেন না।"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"যুক্ত করা <xliff:g id="DEVICE_NAME">%1$s</xliff:g> প্রত্যাখ্যান করেছে।"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi বন্ধ৷"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi এর সংযোগ বিচ্ছিন্ন হয়েছে৷"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi এ একটি দণ্ড৷"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi এ দুইটি দণ্ড৷"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi এ তিনটি দণ্ড৷"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi এ সম্পূর্ণ সিগন্যাল৷"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"সরানো অ্যাপ্লিকেশানগুলি"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"সরানো অ্যাপ্লিকেশানগুলি এবং ব্যবহারকারীগণ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB টেদারিং"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"পোর্টেবল হটস্পট"</string>
+    <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="8101244883654409696">"কর্মস্থলের প্রোফাইল"</string>
+    <string name="user_guest" msgid="8475274842845401871">"অতিথি"</string>
+    <string name="unknown" msgid="1592123443519355854">"অজানা"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"ব্যবহারকারী: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ca/arrays.xml b/packages/SettingsLib/res/values-ca/arrays.xml
new file mode 100644
index 0000000..1bcbe6e
--- /dev/null
+++ b/packages/SettingsLib/res/values-ca/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"S\'està cercant..."</item>
+    <item msgid="8513729475867537913">"S\'està connectant…"</item>
+    <item msgid="515055375277271756">"S\'està autenticant…"</item>
+    <item msgid="1943354004029184381">"S\'està obtenint l\'adreça IP…"</item>
+    <item msgid="4221763391123233270">"Connectat"</item>
+    <item msgid="624838831631122137">"Suspesa"</item>
+    <item msgid="7979680559596111948">"S\'està desconnectant..."</item>
+    <item msgid="1634960474403853625">"Desconnectada"</item>
+    <item msgid="746097431216080650">"Incorrecte"</item>
+    <item msgid="6367044185730295334">"Bloquejada"</item>
+    <item msgid="503942654197908005">"S\'està evitant temporalment una connexió feble"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"S\'està cercant..."</item>
+    <item msgid="355508996603873860">"S\'està connectant a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"S\'està autenticant amb <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"S\'està obtenint l\'adreça IP de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connectat a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspesa"</item>
+    <item msgid="7698638434317271902">"S\'està desconnectant de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desconnectada"</item>
+    <item msgid="8578370891960825148">"Incorrecte"</item>
+    <item msgid="5660739516542454527">"Bloquejada"</item>
+    <item msgid="1805837518286731242">"S\'està evitant temporalment una connexió feble"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
new file mode 100644
index 0000000..81a7cb9
--- /dev/null
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No es poden cercar xarxes"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Cap"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Desat"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desactivat"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuració d\'IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de connexió Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema d\'autenticació"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora de l\'abast"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No s\'ha detectat accés a Internet, no s\'hi tornarà a connectar automàticament."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Desat per <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connectat mitjançant l\'assistent de Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connectada mitjançant %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible mitjançant %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connectada, sense Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconnectat"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"S\'està desconnectant..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"S\'està connectant…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connectat"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"S\'està vinculant..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connectats (sense telèfon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connectat (sense fitxers multimèdia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connectat (no hi ha accés als missatges)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connectat (sense telèfon o disp. mult.)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Àudio multimèdia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Àudio del telèfon"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferència del fitxer"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositiu d\'entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Accés a Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartir contactes"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"S\'utilitza per compartir contactes."</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Connexió compartida a Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Accés al missatge"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accés a la SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connectat a l\'àudio del mitjà"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connectat a àudio del telèfon"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connectat al servidor de transferència de fitxers"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connectat a un mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connectat a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"No està connectat al servidor de transferència de fitxers"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connectat a dispositiu d\'entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connectat al dispositiu per a accés a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"S\'està compartint la connexió a Internet amb el dispositiu"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilitza\'l per a l\'accés a Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilitza per al mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilitza per a l\'accés a la SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilitza per a l\'àudio del mitjà"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilitza-ho per a l\'àudio del telèfon"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilitza per a la transferència de fitxers"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilitza per a entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincula"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"VINCULA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel·la"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"La vinculació permet accedir als contactes i a l\'historial de trucades quan el dispositiu està connectat."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"No s\'ha pogut vincular amb <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No s\'ha pogut vincular amb <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, perquè el PIN o la contrasenya són incorrectes."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No es pot comunicar amb <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vinculació rebutjada per <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desactivada."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconnectada."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Senyal Wi-Fi: una barra."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Senyal Wi-Fi: dues barres."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Senyal Wi-Fi: tres barres."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Senyal Wi-Fi: complet."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicacions eliminades"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicacions i usuaris eliminats"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ancoratge d\'USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portàtil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ancoratge de Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Ancoratge a xarxa"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Ancoratge a la xarxa i zona Wi-Fi"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil professional"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Convidat"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconegut"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuari: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"S\'han definit alguns valors predeterminats"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No s\'ha definit cap valor predeterminat"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-cs/arrays.xml b/packages/SettingsLib/res/values-cs/arrays.xml
new file mode 100644
index 0000000..d990f46
--- /dev/null
+++ b/packages/SettingsLib/res/values-cs/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Vyhledávání..."</item>
+    <item msgid="8513729475867537913">"Připojování..."</item>
+    <item msgid="515055375277271756">"Ověřování..."</item>
+    <item msgid="1943354004029184381">"Načítání IP adresy…"</item>
+    <item msgid="4221763391123233270">"Připojeno"</item>
+    <item msgid="624838831631122137">"Pozastaveno"</item>
+    <item msgid="7979680559596111948">"Odpojování..."</item>
+    <item msgid="1634960474403853625">"Odpojeno"</item>
+    <item msgid="746097431216080650">"Neúspěšné"</item>
+    <item msgid="6367044185730295334">"Blokováno"</item>
+    <item msgid="503942654197908005">"Dočasné předcházení slabému připojení"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Vyhledávání..."</item>
+    <item msgid="355508996603873860">"Připojování k síti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Ověřování v síti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Získávání IP adresy ze sítě <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Připojeno k síti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Pozastaveno"</item>
+    <item msgid="7698638434317271902">"Odpojování od sítě <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Odpojeno"</item>
+    <item msgid="8578370891960825148">"Neúspěšné"</item>
+    <item msgid="5660739516542454527">"Blokováno"</item>
+    <item msgid="1805837518286731242">"Dočasné předcházení slabému připojení"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
new file mode 100644
index 0000000..663ed08
--- /dev/null
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nelze hledat sítě"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Žádné"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Uloženo"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Vypnuto"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Selhání konfigurace protokolu IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Selhání připojení Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s ověřením"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nebyl zjištěn žádný přístup k internetu, připojení nebude automaticky obnoveno."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Uloženo uživatelem <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Připojeno pomocí asistenta připojení Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Připojeno prostřednictvím %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupné prostřednictvím %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Připojeno, není k dispozici internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Odpojeno"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Odpojování..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Připojování..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Připojeno"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Párování..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Připojeno (žádný telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Připojeno (žádná média)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Připojeno (bez přístupu ke zprávám)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Připojeno (žádný telefon nebo média)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk médií"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefonu"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Přenos souborů"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Vstupní zařízení"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Přístup k internetu"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Sdílení kontaktů"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Použít ke sdílení kontaktů"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Sdílení internetového připojení"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Přístup ke zprávám"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Přístup k SIM kartě"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Připojeno ke zvukovému médiu"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Připojeno k náhlavní soupravě"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Připojeno k serveru pro přenos dat"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Připojeno k mapě"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Připojeno k SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nepřipojeno k serveru pro přenos souborů"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Připojeno ke vstupnímu zařízení"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Připojeno k zařízení za účelem přístupu k internetu"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Místní internetové připojení je sdíleno se zařízením"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Použít pro přístup k internetu"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Použít pro mapu"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Používat pro přístup k SIM kartě"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Umožňuje připojení zvukového média"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Umožňuje připojení náhlavní soupravy"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Použít pro přenos souborů"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Použít pro vstup"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párovat"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROVAT"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Zrušit"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Párováním připojenému zařízení udělíte přístup ke svým kontaktům a historii volání."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nelze párovat se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nelze párovat se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Kód PIN nebo přístupový klíč je nesprávný."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Se zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nelze navázat komunikaci."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Párování odmítnuto zařízením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Síť Wi-Fi je vypnuta."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Síť Wi-Fi je odpojena."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi – jedna čárka."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi – dvě čárky."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi – tři čárky."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi – plný signál."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odebrané aplikace"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odebrané aplikace a odebraní uživatelé"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Připojení přes USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Přenosný hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Připojení přes Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Sdílené připojení"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Sdílené připojení a přenosný hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Pracovní profil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Host"</string>
+    <string name="unknown" msgid="1592123443519355854">"Neznámé"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Uživatel: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Je nastaveno několik výchozích hodnot"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nejsou nastaveny žádné výchozí hodnoty"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-da/arrays.xml b/packages/SettingsLib/res/values-da/arrays.xml
new file mode 100644
index 0000000..a8c2a45
--- /dev/null
+++ b/packages/SettingsLib/res/values-da/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scanner ..."</item>
+    <item msgid="8513729475867537913">"Opretter forbindelse..."</item>
+    <item msgid="515055375277271756">"Godkender..."</item>
+    <item msgid="1943354004029184381">"Henter IP-adresse…"</item>
+    <item msgid="4221763391123233270">"Tilsluttet"</item>
+    <item msgid="624838831631122137">"Sat på pause"</item>
+    <item msgid="7979680559596111948">"Afbryder ..."</item>
+    <item msgid="1634960474403853625">"Afbrudt"</item>
+    <item msgid="746097431216080650">"Mislykkedes"</item>
+    <item msgid="6367044185730295334">"Blokeret"</item>
+    <item msgid="503942654197908005">"Undgår midlertidigt dårlig forbindelse"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scanner ..."</item>
+    <item msgid="355508996603873860">"Opretter forbindelse til <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ..."</item>
+    <item msgid="554971459996405634">"Godkender med <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ..."</item>
+    <item msgid="7928343808033020343">"Henter IP-adresse fra <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ..."</item>
+    <item msgid="8937994881315223448">"Forbundet til <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Sat på pause"</item>
+    <item msgid="7698638434317271902">"Afbryder fra <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ..."</item>
+    <item msgid="197508606402264311">"Afbrudt"</item>
+    <item msgid="8578370891960825148">"Mislykkedes"</item>
+    <item msgid="5660739516542454527">"Blokeret"</item>
+    <item msgid="1805837518286731242">"Undgår midlertidigt dårlig forbindelse"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
new file mode 100644
index 0000000..333ed05
--- /dev/null
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Der kan ikke søges efter netværk"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Gemt"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiveret"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurationsfejl"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-forbindelsesfejl"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem med godkendelse"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ikke inden for rækkevidde"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Der blev ikke fundet nogen internetadgang. Forbindelsen bliver ikke automatisk genoprettet."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Gemt af <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Forbindelse via Wi-Fi-assistent"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilsluttet via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgængelig via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tilsluttet – intet internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Afbrudt"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Afbryder ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Opretter forbindelse..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Tilsluttet"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Parrer..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Forbundet (ingen telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tilsluttet (intet medie)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Forbundet (ingen adgang til meddelelse)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Forbundet (ingen telefon eller medier)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medielyd"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefonlyd"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverførsel"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inputenhed"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetadgang"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deling af kontaktpersoner"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Brug til deling af kontaktpersoner"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling af internetforbindelse"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Adgang til meddelelse"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-adgang"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Forbundet til medielyd"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Forbundet til telefonlyd"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Forbundet til filoverførselsserver"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Forbundet til kort"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Sluttet til SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ikke forbundet til filoverførselsserver"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Forbundet til inputenhed"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tilsluttet enhed/internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deler lokal internetforbindelse med enhed"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Brug til internetadgang"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Brug til kort"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Brug til SIM-adgang"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Brug til medielyd"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Brug til telefonlyd"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Brug til filoverførsel"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Brug til input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCEPTÉR PARRING"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuller"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parring giver adgang til dine kontaktpersoner og din opkaldshistorik, når enhederne er forbundet."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Der kunne ikke parres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund af en forkert pinkode eller adgangsnøgle."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Der kan ikke kommunikeres med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Parring afvist af <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi er slået fra."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi er afbrudt."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi har én bjælke."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi har to bjælker."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi har tre bjælker."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi har fuldt signal."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjernede apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjernede apps og brugere"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Netdeling via USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Netdeling via Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Netdeling"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Netdeling og hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Arbejdsprofil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gæst"</string>
+    <string name="unknown" msgid="1592123443519355854">"Ukendt"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Bruger: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Der er angivet nogle standarder"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Der er ikke angivet nogen standarder"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-de/arrays.xml b/packages/SettingsLib/res/values-de/arrays.xml
new file mode 100644
index 0000000..6772c7d
--- /dev/null
+++ b/packages/SettingsLib/res/values-de/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scan läuft…"</item>
+    <item msgid="8513729475867537913">"Verbindung wird hergestellt..."</item>
+    <item msgid="515055375277271756">"Authentifizierung..."</item>
+    <item msgid="1943354004029184381">"IP-Adresse wird abgerufen..."</item>
+    <item msgid="4221763391123233270">"Verbunden"</item>
+    <item msgid="624838831631122137">"Angehalten"</item>
+    <item msgid="7979680559596111948">"Verbindung wird getrennt..."</item>
+    <item msgid="1634960474403853625">"Nicht verbunden"</item>
+    <item msgid="746097431216080650">"Nicht erfolgreich"</item>
+    <item msgid="6367044185730295334">"Blockiert"</item>
+    <item msgid="503942654197908005">"Schlechte Internetverbindung wird vorübergehend vermieden."</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scan läuft…"</item>
+    <item msgid="355508996603873860">"Verbindung mit <xliff:g id="NETWORK_NAME">%1$s</xliff:g> wird hergestellt..."</item>
+    <item msgid="554971459996405634">"Authentifizierung mit <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"IP-Adresse wird von <xliff:g id="NETWORK_NAME">%1$s</xliff:g> abgerufen..."</item>
+    <item msgid="8937994881315223448">"Verbunden mit <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Angehalten"</item>
+    <item msgid="7698638434317271902">"Verbindung mit <xliff:g id="NETWORK_NAME">%1$s</xliff:g> wird getrennt..."</item>
+    <item msgid="197508606402264311">"Nicht verbunden"</item>
+    <item msgid="8578370891960825148">"Nicht erfolgreich"</item>
+    <item msgid="5660739516542454527">"Blockiert"</item>
+    <item msgid="1805837518286731242">"Schlechte Internetverbindung wird vorübergehend vermieden."</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
new file mode 100644
index 0000000..cc0990d
--- /dev/null
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Netzwerkscan nicht möglich"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Keine"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Gespeichert"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Deaktiviert"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-Konfigurationsfehler"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN-Verbindungsfehler"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentifizierungsproblem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Nicht in Reichweite"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Keine Internetverbindung erkannt, es kann nicht automatisch eine Verbindung hergestellt werden."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Gespeichert von <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Über WLAN-Assistenten verbunden"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Über %1$s verbunden"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Verfügbar über %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Verbunden, kein Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Nicht verbunden"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbindung wird getrennt..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Verbindung wird hergestellt..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Verbunden"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing läuft…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Verbunden (kein Telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Verbunden (außer Audiomedien)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbunden (ohne Nachrichtenzugriff)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Verbunden (außer Telefon- und Audiomedien)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-Audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefon-Audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dateiübertragung"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Eingabegerät"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetzugriff"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktfreigabe"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Für Kontaktfreigabe nutzen"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Freigabe der Internetverbindung"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Nachrichtenzugriff"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Zugriff auf SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbunden mit  Audiosystem von Medien"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbunden mit Audiosystem des Telefons"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Mit Dateiübertragungsserver verbunden"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Mit Karte verbunden"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Mit SAP verbunden"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nicht mit Dateiübertragungsserver verbunden"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Mit einem Eingabegerät verbunden"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Für Internetzugriff an Gerät angeschlossen"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokale Internetverbindung für Gerät freigeben"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Für Internetzugriff verwenden"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Für Karte verwenden"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Für SIM-Zugriff verwenden"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Für Audiosystem von Medien verwenden"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Für Audiosystem des Telefons verwenden"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Für Dateiübertragung verwenden"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Für Eingabe verwenden"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pairing durchführen"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"Pairing durchführen"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Abbrechen"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Über das Pairing kann auf Ihre Kontakte und auf Ihren Anrufverlauf zugegriffen werden, wenn eine Verbindung besteht."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Pairing mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> war nicht möglich, weil die eingegebene PIN oder der Zugangscode falsch ist."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kommunikation mit <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ist nicht möglich."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Verbindung wurde von <xliff:g id="DEVICE_NAME">%1$s</xliff:g> abgelehnt."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN: aus"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"WLAN getrennt"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WLAN: ein Balken"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WLAN: zwei Balken"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WLAN: drei Balken"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WLAN: volle Signalstärke"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Entfernte Apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Entfernte Apps und Nutzer"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-Tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Mobiler Hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-Tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering &amp; mobiler Hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Arbeitsprofil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gast"</string>
+    <string name="unknown" msgid="1592123443519355854">"Unbekannt"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Nutzer: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Einige Standardeinstellungen festgelegt"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Keine Standardeinstellungen festgelegt"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-el/arrays.xml b/packages/SettingsLib/res/values-el/arrays.xml
new file mode 100644
index 0000000..f616547
--- /dev/null
+++ b/packages/SettingsLib/res/values-el/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Σύνδεση..."</item>
+    <item msgid="515055375277271756">"Έλεγχος ταυτότητας..."</item>
+    <item msgid="1943354004029184381">"Λήψη διεύθυνσης IP…"</item>
+    <item msgid="4221763391123233270">"Συνδεδεμένο"</item>
+    <item msgid="624838831631122137">"Σε αναστολή"</item>
+    <item msgid="7979680559596111948">"Αποσύνδεση..."</item>
+    <item msgid="1634960474403853625">"Αποσυνδέθηκε"</item>
+    <item msgid="746097431216080650">"Ανεπιτυχής"</item>
+    <item msgid="6367044185730295334">"Αποκλεισμένο"</item>
+    <item msgid="503942654197908005">"Προσωρινή αποφυγή αδύναμης σύνδεσης"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"Λήψη διεύθυνσης IP από <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Συνδεδεμένο σε <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Σε αναστολή"</item>
+    <item msgid="7698638434317271902">"Αποσύνδεση από <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Αποσυνδέθηκε"</item>
+    <item msgid="8578370891960825148">"Ανεπιτυχής"</item>
+    <item msgid="5660739516542454527">"Αποκλεισμένο"</item>
+    <item msgid="1805837518286731242">"Προσωρινή αποφυγή αδύναμης σύνδεσης"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
new file mode 100644
index 0000000..1d1c564
--- /dev/null
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Δεν είναι δυνατή η σάρωση για δίκτυα"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Εκτός εμβέλειας"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Δεν εντοπίστηκε καμία πρόσβαση στο διαδίκτυο, δεν θα γίνει αυτόματη επανασύνδεση."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Αποθηκεύτηκε από <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Σύνδεση μέσω βοηθού Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Συνδέθηκε μέσω %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Διαθέσιμο μέσω %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Συνδέθηκε, χωρίς διαδίκτυο"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Αποσυνδέθηκε"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Αποσύνδεση..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Σύνδεση..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Συνδεδεμένο"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Σύζευξη..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Συνδεδεμένο (όχι τηλ.)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Συνδεδεμένο (όχι μέσα)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Συνδεδεμένο (χωρίς πρόσβαση μηνύματος)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Συνδεδεμένο (χωρίς τηλέφωνο ή πολυμέσα)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Ήχος πολυμέσων"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Ήχος τηλεφώνου"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Μεταφορά αρχείου"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Συσκευή εισόδου"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Πρόσβαση στο Διαδίκτυο"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Κοινή χρήση επαφών"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Για κοινή χρήση επαφών"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Κοινή χρήση σύνδεσης στο Διαδίκτυο"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Πρόσβαση στο μήνυμα"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Πρόσβαση SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Συνδέθηκε σε ήχο πολυμέσων"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Συνδεδεμένο στον ήχο τηλεφώνου"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Συνδεδεμένο σε διακομιστή μεταφοράς αρχείων"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Συνδεδεμένο στο χάρτη"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Συνδέθηκε σε SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Δεν έχει συνδεθεί σε διακομιστή μεταφοράς αρχείων"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Συνδέθηκε σε συσκευή εισόδου"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Συνδέθηκε με συσκευή με πρόσβ. στο Διαδ."</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Κοιν. χρ. σύνδ. στο Διαδ. με συσκευή"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Χρήση για την πρόσβαση στο Διαδίκτυο"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Χρήση για χάρτη"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Χρήση για πρόσβαση στη SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Χρήση για ήχο πολυμέσων"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Χρήση για ήχο τηλεφώνου"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Χρήση για τη μεταφορά αρχείων"</string>
+    <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_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 ή κλειδιού πρόσβασης."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Δεν είναι δυνατή η σύνδεση με τη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Η ζεύξη απορρίφθηκε από τη συσκευή <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi ανενεργό."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Το Wi-Fi έχει αποσυνδεθεί."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Μία γραμμή Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Δύο γραμμές Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Τρεις γραμμές Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Άριστο σήμα Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Λειτουργικό σύστημα Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Εφαρμογές που καταργήθηκαν"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Εφαρμογές και χρήστες που έχουν καταργηθεί"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Πρόσδεση USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Φορητό σημείο πρόσβασης"</string>
+    <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="8101244883654409696">"Προφίλ εργασίας"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Επισκέπτης"</string>
+    <string name="unknown" msgid="1592123443519355854">"Άγνωστο"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Χρήστης: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/arrays.xml b/packages/SettingsLib/res/values-en-rAU/arrays.xml
new file mode 100644
index 0000000..8fa3918
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rAU/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scanning…"</item>
+    <item msgid="8513729475867537913">"Connecting…"</item>
+    <item msgid="515055375277271756">"Authenticating…"</item>
+    <item msgid="1943354004029184381">"Obtaining IP address…"</item>
+    <item msgid="4221763391123233270">"Connected"</item>
+    <item msgid="624838831631122137">"Suspended"</item>
+    <item msgid="7979680559596111948">"Disconnecting…"</item>
+    <item msgid="1634960474403853625">"Disconnected"</item>
+    <item msgid="746097431216080650">"Unsuccessful"</item>
+    <item msgid="6367044185730295334">"Blocked"</item>
+    <item msgid="503942654197908005">"Temporarily avoiding poor connection"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scanning…"</item>
+    <item msgid="355508996603873860">"Connecting to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Authenticating with <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtaining IP address from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connected to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspended"</item>
+    <item msgid="7698638434317271902">"Disconnecting from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Disconnected"</item>
+    <item msgid="8578370891960825148">"Unsuccessful"</item>
+    <item msgid="5660739516542454527">"Blocked"</item>
+    <item msgid="1805837518286731242">"Temporarily avoiding poor connection"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..99fd61e
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"None"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connecting…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connected"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connected (no phone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Phone audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Input device"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internet access"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Contact sharing"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Use for contact sharing"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internet connection sharing"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Message Access"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connected to map"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Pairing grants access to your contacts and call history when connected."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi off."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi two bars."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi three bars."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi signal full."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering &amp; portable hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Work profile"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Guest"</string>
+    <string name="unknown" msgid="1592123443519355854">"Unknown"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"User: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Some defaults set"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No defaults set"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/arrays.xml b/packages/SettingsLib/res/values-en-rGB/arrays.xml
new file mode 100644
index 0000000..8fa3918
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rGB/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scanning…"</item>
+    <item msgid="8513729475867537913">"Connecting…"</item>
+    <item msgid="515055375277271756">"Authenticating…"</item>
+    <item msgid="1943354004029184381">"Obtaining IP address…"</item>
+    <item msgid="4221763391123233270">"Connected"</item>
+    <item msgid="624838831631122137">"Suspended"</item>
+    <item msgid="7979680559596111948">"Disconnecting…"</item>
+    <item msgid="1634960474403853625">"Disconnected"</item>
+    <item msgid="746097431216080650">"Unsuccessful"</item>
+    <item msgid="6367044185730295334">"Blocked"</item>
+    <item msgid="503942654197908005">"Temporarily avoiding poor connection"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scanning…"</item>
+    <item msgid="355508996603873860">"Connecting to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Authenticating with <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtaining IP address from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connected to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspended"</item>
+    <item msgid="7698638434317271902">"Disconnecting from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Disconnected"</item>
+    <item msgid="8578370891960825148">"Unsuccessful"</item>
+    <item msgid="5660739516542454527">"Blocked"</item>
+    <item msgid="1805837518286731242">"Temporarily avoiding poor connection"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..99fd61e
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"None"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connecting…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connected"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connected (no phone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Phone audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Input device"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internet access"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Contact sharing"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Use for contact sharing"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internet connection sharing"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Message Access"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connected to map"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Pairing grants access to your contacts and call history when connected."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi off."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi two bars."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi three bars."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi signal full."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering &amp; portable hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Work profile"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Guest"</string>
+    <string name="unknown" msgid="1592123443519355854">"Unknown"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"User: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Some defaults set"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No defaults set"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/arrays.xml b/packages/SettingsLib/res/values-en-rIN/arrays.xml
new file mode 100644
index 0000000..8fa3918
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scanning…"</item>
+    <item msgid="8513729475867537913">"Connecting…"</item>
+    <item msgid="515055375277271756">"Authenticating…"</item>
+    <item msgid="1943354004029184381">"Obtaining IP address…"</item>
+    <item msgid="4221763391123233270">"Connected"</item>
+    <item msgid="624838831631122137">"Suspended"</item>
+    <item msgid="7979680559596111948">"Disconnecting…"</item>
+    <item msgid="1634960474403853625">"Disconnected"</item>
+    <item msgid="746097431216080650">"Unsuccessful"</item>
+    <item msgid="6367044185730295334">"Blocked"</item>
+    <item msgid="503942654197908005">"Temporarily avoiding poor connection"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scanning…"</item>
+    <item msgid="355508996603873860">"Connecting to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Authenticating with <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtaining IP address from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connected to <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspended"</item>
+    <item msgid="7698638434317271902">"Disconnecting from <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Disconnected"</item>
+    <item msgid="8578370891960825148">"Unsuccessful"</item>
+    <item msgid="5660739516542454527">"Blocked"</item>
+    <item msgid="1805837518286731242">"Temporarily avoiding poor connection"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..99fd61e
--- /dev/null
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Can\'t scan for networks"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"None"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Saved"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disabled"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Configuration Failure"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi Connection Failure"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authentication problem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Not in range"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No Internet Access Detected, won\'t automatically reconnect."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Saved by <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connected via Wi‑Fi assistant"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connected via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Available via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connected, no Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnected"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnecting…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connecting…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connected"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pairing…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connected (no phone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connected (no media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connected (no message access)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connected (no phone or media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Phone audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"File transfer"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Input device"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internet access"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Contact sharing"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Use for contact sharing"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internet connection sharing"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Message Access"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Access"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connected to media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connected to phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connected to file-transfer server"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connected to map"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connected to SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Not connected to file-transfer server"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connected to input device"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connected to device for Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Sharing local Internet connection with device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Use for Internet access"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Use for map"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use for SIM access"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Use for media audio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Use for phone audio"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Use for file transfer"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Use for input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pair"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAIR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancel"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Pairing grants access to your contacts and call history when connected."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi off."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi disconnected."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi one bar."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi two bars."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi three bars."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi signal full."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Removed apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Removed apps and users"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering &amp; portable hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Work profile"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Guest"</string>
+    <string name="unknown" msgid="1592123443519355854">"Unknown"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"User: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Some defaults set"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No defaults set"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/arrays.xml b/packages/SettingsLib/res/values-es-rUS/arrays.xml
new file mode 100644
index 0000000..5947056
--- /dev/null
+++ b/packages/SettingsLib/res/values-es-rUS/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Explorando..."</item>
+    <item msgid="8513729475867537913">"Conectando…"</item>
+    <item msgid="515055375277271756">"Autenticando…"</item>
+    <item msgid="1943354004029184381">"Obteniendo la dirección IP…"</item>
+    <item msgid="4221763391123233270">"Conectado"</item>
+    <item msgid="624838831631122137">"Suspendido"</item>
+    <item msgid="7979680559596111948">"Desconectando…"</item>
+    <item msgid="1634960474403853625">"Desconectado"</item>
+    <item msgid="746097431216080650">"Incorrecto"</item>
+    <item msgid="6367044185730295334">"Bloqueada"</item>
+    <item msgid="503942654197908005">"Desactivando mala conexión  temporalmente"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Explorando..."</item>
+    <item msgid="355508996603873860">"Conectando a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autenticando con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obteniendo dirección IP de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendido"</item>
+    <item msgid="7698638434317271902">"Desconectando de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desconectado"</item>
+    <item msgid="8578370891960825148">"Incorrecto"</item>
+    <item msgid="5660739516542454527">"Bloqueada"</item>
+    <item msgid="1805837518286731242">"Desactivando mala conexión  temporalmente"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..a912db2
--- /dev/null
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No se pueden buscar las redes."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ninguna"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Guardada"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inhabilitada"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuración IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de alcance"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No se detectó el acceso a Internet. No se volverá a conectar de forma automática."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conexión por asistente de Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conexión a través de %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectado a Wi-Fi, sin conexión a Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Conectando…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Vinculando..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectado (sin teléfono)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sin audio multimedia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sin acceso a mensajes)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sin tel. ni audio multimedia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio del dispositivo"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de archivos"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acceso a Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartir contactos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utilizar para compartir contactos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartir conexión a Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acceso a mensajes"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado al audio multimedia"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado al audio del dispositivo"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado al servidor de transferencia de archivo"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectado al mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conexión a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"No conectado al servidor de transferencia de archivo"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado a dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado a un dispositivo para acceder a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Conexión a Internet local compartida con dispositivo"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizar para acceso a Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Usar para acceder a la SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para el audio multimedia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para el audio del dispositivo"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizar para la transferencia de archivos"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizar para entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincular"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"La sincronización te permite acceder a los contactos y al historial de llamadas cuando el dispositivo está conectado."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que el PIN o la clave de acceso son incorrectos."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No se puede establecer la comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vínculo rechazado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi inhabilitado"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Una barra de Wi-Fi"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dos barras de Wi-Fi"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tres barras de Wi-Fi"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Señal de Wi-Fi excelente"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaciones y usuarios eliminados"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Anclaje a red USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Anclaje a red Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Anclaje a red"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Anclaje a red y zona portátil"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil de trabajo"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Invitado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconocido"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuario: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Hay algunas configuraciones predeterminadas establecidas."</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No hay configuraciones predeterminadas establecidas."</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
new file mode 100644
index 0000000..ba51a81
--- /dev/null
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Buscando..."</item>
+    <item msgid="8513729475867537913">"Estableciendo conexión..."</item>
+    <item msgid="515055375277271756">"Autenticando..."</item>
+    <item msgid="1943354004029184381">"Obteniendo dirección IP…"</item>
+    <item msgid="4221763391123233270">"Conexión establecida"</item>
+    <item msgid="624838831631122137">"Suspendida"</item>
+    <item msgid="7979680559596111948">"Desconectando..."</item>
+    <item msgid="1634960474403853625">"Desconectada"</item>
+    <item msgid="746097431216080650">"Con error"</item>
+    <item msgid="6367044185730295334">"Bloqueada"</item>
+    <item msgid="503942654197908005">"Inhabilitando conexión inestable temporalmente..."</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Buscando..."</item>
+    <item msgid="355508996603873860">"Estableciendo conexión con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Autenticando con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obteniendo dirección IP de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Conexión establecida con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendida"</item>
+    <item msgid="7698638434317271902">"Desconectando de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Desconectada"</item>
+    <item msgid="8578370891960825148">"Con error"</item>
+    <item msgid="5660739516542454527">"Bloqueada"</item>
+    <item msgid="1805837518286731242">"Inhabilitando conexión inestable temporalmente..."</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
new file mode 100644
index 0000000..b6dcb9e
--- /dev/null
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"No se puede buscar redes."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ninguna"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Guardado"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inhabilitado"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Error de configuración de IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Error de conexión Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Error de autenticación"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuera de rango"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"No se ha detectado acceso a Internet, no se volverá a conectar automáticamente."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Guardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado a través de asistente Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible a través de %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conexión sin Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectada"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Estableciendo conexión…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Vinculando…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectado (sin teléfono)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sin audio multimedia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sin acceso a mensajes)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sin teléfono ni multimedia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio del teléfono"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de archivos"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acceso a Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartir contactos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usar para compartir contactos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartir conexión a Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acceso a mensajes"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso a tarjeta SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado al audio del medio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado al audio del teléfono"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado con el servidor de transferencia de archivos"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectado a mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Sin conexión con el servidor de transferencia de archivos"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado a dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado para acceso a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compartiendo conexión a Internet con el dispositivo"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acceder a Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizar para acceso a tarjeta SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para audio de medio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para audio del teléfono"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Uso de la transferencia de archivos"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Vincular"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"VINCULAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"La vinculación permite acceder a tus contactos y al historial de llamadas cuando el dispositivo está conectado."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"No se ha podido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No se ha podido vincular con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> porque la clave de acceso o el PIN son incorrectos."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No se puede establecer comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vinculación rechazada por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desactivado."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Una barra de Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dos barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tres barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Señal de Wi-Fi al máximo."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicaciones eliminadas"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usuarios y aplicaciones eliminados"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Compartir por USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona Wi-Fi portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Compartir por Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Compartir Internet"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Compartir Internet y zona Wi-Fi"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil de trabajo"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Invitado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconocido"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuario: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Se han establecido algunos valores predeterminados"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"No se han establecido valores predeterminados"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/arrays.xml b/packages/SettingsLib/res/values-et-rEE/arrays.xml
new file mode 100644
index 0000000..2a8f69b
--- /dev/null
+++ b/packages/SettingsLib/res/values-et-rEE/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skannimine…"</item>
+    <item msgid="8513729475867537913">"Ühenduse loomine…"</item>
+    <item msgid="515055375277271756">"Autentimine…"</item>
+    <item msgid="1943354004029184381">"IP-aadressi hankimine…"</item>
+    <item msgid="4221763391123233270">"Ühendatud"</item>
+    <item msgid="624838831631122137">"Peatatud"</item>
+    <item msgid="7979680559596111948">"Ühenduse katkestamine…"</item>
+    <item msgid="1634960474403853625">"Ühendus katkestatud"</item>
+    <item msgid="746097431216080650">"Ebaõnnestus"</item>
+    <item msgid="6367044185730295334">"Blokeeritud"</item>
+    <item msgid="503942654197908005">"Kehva ühenduse ajutine vältimine"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skannimine…"</item>
+    <item msgid="355508996603873860">"Ühendamine võrguga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autentimine võrguga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"IP-aadressi hankimine võrgust <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Ühendatud võrguga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Peatatud"</item>
+    <item msgid="7698638434317271902">"Ühenduse katkestamine võrguga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Ühendus katkestatud"</item>
+    <item msgid="8578370891960825148">"Ebaõnnestus"</item>
+    <item msgid="5660739516542454527">"Blokeeritud"</item>
+    <item msgid="1805837518286731242">"Kehva ühenduse ajutine vältimine"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
new file mode 100644
index 0000000..ee92078
--- /dev/null
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Võrke ei saa kontrollida"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Puudub"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Salvestatud"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Keelatud"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP seadistamise ebaõnnestumine"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-ühenduse viga"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentimise probleem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Pole vahemikus"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Interneti-ühendust ei tuvastatud, seadet ei ühendata automaatselt."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Salvestas: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Ühendatud WiFi-abi kaudu"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Ühendatud üksuse %1$s kaudu"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Saadaval üksuse %1$s kaudu"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ühendatud, Interneti-ühendus puudub"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ühendus katkestatud"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ühenduse katkestamine ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Ühendamine ..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Ühendatud"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Sidumine ..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ühendatud (telefoni pole)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ühendatud (meediat pole)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ühendatud (sõnumita juurdepääs)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ühendatud (pole telefoni ega meediat)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Meedia heli"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefoni heli"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failiedastus"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Sisendseade"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetti juurdepääs"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontakti jagamine"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Kasutamine kontaktide jagamiseks"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Interneti-ühenduse jagamine"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Juurdepääs sõnumile"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kaardi juurdepääs"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ühendatud meediumiheliga"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ühendatud telefoniheliga"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ühendatud failiedastuse serveriga"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Ühendatud kaardiga"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ühendatud SAP-iga"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ei ole failiedastuse serveriga ühendatud"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ühendatud sisendseade"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ühendatud seadmega Internetti juurdepääsuks"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kohaliku Interneti-ühenduse jagamine seadmega"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Interneti-juurdepääsuks kasutamine"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Kasuta kaardi jaoks"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM-kaardi juurdepääsuks kasutamine"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Kasuta meediumiheli jaoks"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Kasuta telefoniheli jaoks"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Kasutage failide edastamiseks"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Kasutage sisendi jaoks"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seo"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEO"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Tühista"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Sidumine annab ühenduse ajal juurdepääsu kontaktidele ja kõneajaloole."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Ei saanud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> siduda."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ei saanud seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> siduda vale PIN-koodi või parooli tõttu."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Seadmega <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ei saa sidet luua."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> hülgas sidumise."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi on välja lülitatud."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"WiFi-ühendus on katkestatud."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi: üks pulk."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WiFi: kaks pulka."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WiFi: kolm pulka."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WiFi-signaal on tugev."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Eemaldatud rakendused"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Eemaldatud rakendused ja kasutajad"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB jagamine"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Kantav tööpunkt"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetoothi jagamine"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Jagamine"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Jagam. ja kant. kuumkoht"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Tööprofiil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Külaline"</string>
+    <string name="unknown" msgid="1592123443519355854">"Tundmatu"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Kasutaja: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Määratud on mõned vaikevalikud"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Ühtegi vaikevalikut pole määratud"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/arrays.xml b/packages/SettingsLib/res/values-eu-rES/arrays.xml
new file mode 100644
index 0000000..7746f01
--- /dev/null
+++ b/packages/SettingsLib/res/values-eu-rES/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Bilatzen…"</item>
+    <item msgid="8513729475867537913">"Konektatzen…"</item>
+    <item msgid="515055375277271756">"Autentifikatzen…"</item>
+    <item msgid="1943354004029184381">"IP helbidea lortzen…"</item>
+    <item msgid="4221763391123233270">"Konektatuta"</item>
+    <item msgid="624838831631122137">"Etenda"</item>
+    <item msgid="7979680559596111948">"Deskonektatzen…"</item>
+    <item msgid="1634960474403853625">"Deskonektatuta"</item>
+    <item msgid="746097431216080650">"Ezin izan da konektatu"</item>
+    <item msgid="6367044185730295334">"Blokeatuta"</item>
+    <item msgid="503942654197908005">"Konexio ahula aldi baterako saihesten"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Bilatzen…"</item>
+    <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarera konektatzen…"</item>
+    <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarearekin autentifikatzen…"</item>
+    <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarearen IP helbidea lortzen…"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> sarera konektatuta"</item>
+    <item msgid="1330262655415760617">"Etenda"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> saretik deskonektatzen…"</item>
+    <item msgid="197508606402264311">"Deskonektatuta"</item>
+    <item msgid="8578370891960825148">"Ezin izan da konektatu"</item>
+    <item msgid="5660739516542454527">"Blokeatuta"</item>
+    <item msgid="1805837518286731242">"Konexio ahula aldi baterako saihesten"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
new file mode 100644
index 0000000..9b93111
--- /dev/null
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ezin dira sareak bilatu"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Bat ere ez"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Gordeta"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desgaituta"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Ezin izan da konfiguratu IP helbidea"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ezin izan da konektatu Wi-Fi sarera"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikazio-arazoa"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Urrunegi"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ez da hauteman Interneterako sarbiderik. Ez da automatikoki berriro konektatuko."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioak gorde du"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi laguntzailearen bidez konektatuta"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s bidez konektatuta"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s bidez erabilgarri"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Konektatuta, ez dago Interneteko konexiorik"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Deskonektatuta"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Deskonektatzen…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Konektatzen…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Konektatuta"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Parekatzen…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Konektatuta (ez dago telefonorik)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Konektatuta (ez dago euskarririk)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Konektatuta (mezuetarako sarbiderik ez)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Konektatuta (ez dago telef./euskarririk)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Euskarriaren audioa"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefonoaren audioa"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fitxategi-transferentzia"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Sarrerako gailua"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Interneterako sarbidea"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktuak partekatzea"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Erabili kontaktuak partekatzeko"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Interneteko konexioa partekatzea"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Mezuetarako sarbidea"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM txartelerako sarbidea"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Euskarriaren audiora konektatuta"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefonoaren audiora konektatuta"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fitxategi-transferentziako zerbitzarira konektatuta"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Mapara konektatuta"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP sarbide-puntura konektatuta"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fitxategi-transferentziako zerbitzarira konektatu gabe"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Sarrerako gailura konektatuta"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Gailura konektatuta Interneteko sarbiderako"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Tokiko Interneteko konexioa gailu batekin partekatzea"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Erabili Interneteko sarbiderako"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Erabili maparako"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Erabili SIM txartelerako sarbiderako"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Erabili euskarriaren audiorako"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Erabili telefonoaren audiorako"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Erabili fitxategi-transferentziarako"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Erabili idazketarako"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parekatu"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREKATU"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Utzi"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Gailuak parekatzen badituzu, batetik besteko kontaktuak eta deien historia atzitu ahal izango dituzu."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Ezin izan da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin parekatu."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ezin izan da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin parekatu PIN edo pasakode okerra idatzi delako."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ezin da <xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuarekin komunikatu."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> gailuak bikotetzea ukatu du."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Desaktibatuta dago Wi-Fi konexioa."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Deskonektatu egin da Wi-Fi konexioa."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi sarearen barra bat."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi sarearen bi barra."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi sarearen hiru barra."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi sarearen seinalea osoa."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android sistema eragilea"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Kendutako aplikazioak"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Kendutako aplikazioak eta erabiltzaileak"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Konexioa partekatzea (USB)"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Sare publiko eramangarria"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Konexioa partekatzea (Bluetooth)"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Konexioa partekatzea"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Konexioa partekatzea eta sare publikoak"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Laneko profila"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gonbidatua"</string>
+    <string name="unknown" msgid="1592123443519355854">"Ezezaguna"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Erabiltzailea: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Hobespen lehenetsi batzuk ezarrita daude"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Ez dago hobespen lehenetsirik ezarrita"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-fa/arrays.xml b/packages/SettingsLib/res/values-fa/arrays.xml
new file mode 100644
index 0000000..1781c79
--- /dev/null
+++ b/packages/SettingsLib/res/values-fa/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"در حال اتصال…"</item>
+    <item msgid="515055375277271756">"در حال تأیید اعتبار..."</item>
+    <item msgid="1943354004029184381">"‏در حال دریافت آدرس IP..."</item>
+    <item msgid="4221763391123233270">"متصل"</item>
+    <item msgid="624838831631122137">"معلق"</item>
+    <item msgid="7979680559596111948">"در حال قطع اتصال..."</item>
+    <item msgid="1634960474403853625">"اتصال قطع شد"</item>
+    <item msgid="746097431216080650">"ناموفق"</item>
+    <item msgid="6367044185730295334">"مسدود شده"</item>
+    <item msgid="503942654197908005">"جلوگیری موقت از اتصال ضعیف"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"‏در حال دریافت آدرس IP از <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"متصل شد به <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"معلق"</item>
+    <item msgid="7698638434317271902">"اتصال قطع شد از <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"اتصال قطع شد"</item>
+    <item msgid="8578370891960825148">"ناموفق"</item>
+    <item msgid="5660739516542454527">"مسدود شده"</item>
+    <item msgid="1805837518286731242">"جلوگیری موقت از اتصال ضعیف"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
new file mode 100644
index 0000000..081c776
--- /dev/null
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"اسکن شبکه‌ها امکان‌پذیر نیست"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"در محدوده نیست"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"دسترسی به اینترنت شناسایی نشد، به صورت خودکار وصل نمی‌شود."</string>
+    <string name="saved_network" msgid="4352716707126620811">"ذخیره‌شده توسط <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"‏متصل شده از طریق دستیار Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"‏متصل از طریق %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"‏دردسترس از طریق %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"متصل، بدون اینترنت"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"اتصال قطع شد"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"در حال قطع اتصال..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"در حال اتصال…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"متصل"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"در حال مرتبط‌سازی..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"متصل شد (بدون تلفن)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"متصل شد (بدون رسانه)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"متصل (عدم دسترسی به پیام)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"متصل شد (بدون تلفن یا رسانه)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"رسانه صوتی"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"صدای تلفن"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"انتقال فایل"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"دستگاه ورودی"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"دسترسی به اینترنت"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"اشتراک‌گذاری مخاطب"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"استفاده برای اشتراک‌گذاری مخاطب"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"اشتراک‌گذاری اتصال اینترنت"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"دسترسی به پیام"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"دسترسی سیم‌کارت"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"به رسانه صوتی متصل شد"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"به تلفن صوتی متصل شد"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"به سرور انتقال فایل متصل شد"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"به نقشه متصل شد"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"‏متصل به SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"به سرور انتقال فایل متصل نیست"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"به دستگاه ورودی متصل شد"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"برای دسترسی به اینترنت، به دستگاه متصل شد"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"اشتراک‌گذاری اتصال اینترنت محلی با دستگاه"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"استفاده برای دسترسی به اینترنت"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"استفاده برای نقشه"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"استفاده برای دسترسی سیم‌کارت"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"استفاده برای رسانه صوتی"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"استفاده برای تلفن صوتی"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"استفاده برای انتقال فایل"</string>
+    <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_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> انجام نشد."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ارتباط با <xliff:g id="DEVICE_NAME">%1$s</xliff:g> امکان‌پذیر نیست."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> مرتبط‌سازی را رد کرد."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"‏Wi‑Fi خاموش است."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"‏Wi-Fi قطع‌ شد."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"‏یک نوار برای Wi‑Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"‏دو نوار برای Wi‑Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"‏سه نوار برای Wi‑Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"‏قدرت سیگنال Wi‑Fi کامل است."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"‏سیستم عامل Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"برنامه‌های حذف شده"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"برنامه‌ها و کاربران حذف شده"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏اتصال داده با سیم USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"نقطه اتصال قابل حمل"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"اتصال اینترنت با تلفن همراه بلوتوث"</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="8101244883654409696">"نمایه کاری"</string>
+    <string name="user_guest" msgid="8475274842845401871">"مهمان"</string>
+    <string name="unknown" msgid="1592123443519355854">"ناشناس"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"کاربر: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-fi/arrays.xml b/packages/SettingsLib/res/values-fi/arrays.xml
new file mode 100644
index 0000000..76cf49b
--- /dev/null
+++ b/packages/SettingsLib/res/values-fi/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Etsitään..."</item>
+    <item msgid="8513729475867537913">"Yhdistetään…"</item>
+    <item msgid="515055375277271756">"Varmennetaan…"</item>
+    <item msgid="1943354004029184381">"Haetaan IP-osoitetta..."</item>
+    <item msgid="4221763391123233270">"Yhdistetty"</item>
+    <item msgid="624838831631122137">"Pidätetty"</item>
+    <item msgid="7979680559596111948">"Katkaistaan yhteyttä..."</item>
+    <item msgid="1634960474403853625">"Yhteys katkaistu"</item>
+    <item msgid="746097431216080650">"Epäonnistui"</item>
+    <item msgid="6367044185730295334">"Estetty"</item>
+    <item msgid="503942654197908005">"Vältetään huonoa yhteyttä tilapäisesti"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Etsitään..."</item>
+    <item msgid="355508996603873860">"Yhdistetään verkkoon <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Varmennetaan verkkoon <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Haetaan IP-osoitetta verkosta <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Yhdistetty verkkoon <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Pidätetty"</item>
+    <item msgid="7698638434317271902">"Katkaistaan yhteys verkosta <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Yhteys katkaistu"</item>
+    <item msgid="8578370891960825148">"Epäonnistui"</item>
+    <item msgid="5660739516542454527">"Estetty"</item>
+    <item msgid="1805837518286731242">"Vältetään huonoa yhteyttä tilapäisesti"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
new file mode 100644
index 0000000..29bcf11
--- /dev/null
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Verkkoja ei voi etsiä."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ei mitään"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Tallennettu"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Pois käytöstä"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-kokoonpanovirhe"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-yhteysvirhe"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Todennusvirhe"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ei kantoalueella"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetyhteyttä ei havaittu, yhteyttä ei muodosteta automaattisesti uudelleen."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Tallentaja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Yhteys muodostettu Wi‑Fi-apurin kautta"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Yhdistetty seuraavan kautta: %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Käytettävissä seuraavan kautta: %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Yhdistetty, ei internetyhteyttä."</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Yhteys katkaistu"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Katkaistaan yhteyttä..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Yhdistetään…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Yhdistetty"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Laiteparia muodostetaan..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Yhdistetty (ei puhelimen ääntä)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Yhdistetty (ei median ääntä)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Yhdistetty (ei MAP)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Yhdistetty (ei puhelimen/median ääntä)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Median ääni"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Puhelimen ääni"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Tiedostonsiirto"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Syöttölaite"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetyhteys"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Yhteystietojen jakaminen"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Käytä yhteystietojen jakamiseen"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internetyhteyden jakaminen"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"MAP"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kortin käyttö"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Yhdistetty median ääneen"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Yhdistetty puhelimen ääneen"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Yhdistetty tiedostonsiirtopalvelimeen"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"MAP-yhteys"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-yhteys on muodostettu."</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ei yhdistetty tiedostonsiirtopalvelimeen"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Yhdistetty syöttölaitteeseen"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Yhdistetty laitteen internetyhteyteen"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Paikallinen internetyhteys jaetaan laitteen kanssa"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Käytä internetyhteyteen"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Käytä MAP-profiilille"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Käytetään SIM-kortin käyttöoikeuden määrittämiseen."</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Käytä median äänille"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Käytä puhelimen äänille"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Käytä tiedostojen siirtoon"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Käytä syöttöön"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Muodosta laitepari"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"MUODOSTA LAITEPARI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Peruuta"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Laiteparin muodostaminen mahdollistaa yhteystietojen ja soittohistorian käyttämisen yhteyden aikana."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Laiteparin muodostaminen laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g> epäonnistui."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Laiteparia laitteen <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kanssa ei voitu muodostaa, koska PIN-koodi tai avain oli virheellinen."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ei yhteyttä laitteeseen <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Laite <xliff:g id="DEVICE_NAME">%1$s</xliff:g> torjui laitepariyhteyden."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi pois käytöstä"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Ei Wi-Fi-yhteyttä"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-signaali – yksi palkki"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi-signaali – kaksi palkkia"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi-signaali – kolme palkkia"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Vahva Wi-Fi-signaali"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android-käyttöjärjestelmä"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Poistetut sovellukset"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Poistetut sovellukset ja käyttäjät"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Jaettu yhteys USB:n kautta"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Kannettava yhteyspiste"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Jaettu Bluetooth-yhteys"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Jaettu yhteys"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Jaettu yhteys ja kannettava yhteyspiste"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Työprofiili"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Vieras"</string>
+    <string name="unknown" msgid="1592123443519355854">"Tuntematon"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Käyttäjä: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Joitakin oletuksia on asetettu."</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Oletuksia ei asetettu."</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/arrays.xml b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
new file mode 100644
index 0000000..991d824
--- /dev/null
+++ b/packages/SettingsLib/res/values-fr-rCA/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Recherche…"</item>
+    <item msgid="8513729475867537913">"Connexion en cours…"</item>
+    <item msgid="515055375277271756">"Authentification en cours…"</item>
+    <item msgid="1943354004029184381">"Récupération de l\'adresse IP…"</item>
+    <item msgid="4221763391123233270">"Connecté"</item>
+    <item msgid="624838831631122137">"Suspendu"</item>
+    <item msgid="7979680559596111948">"Déconnexion…"</item>
+    <item msgid="1634960474403853625">"Déconnecté"</item>
+    <item msgid="746097431216080650">"Échec"</item>
+    <item msgid="6367044185730295334">"Bloqué"</item>
+    <item msgid="503942654197908005">"Mauvaise connexion évitée momentanément"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Recherche…"</item>
+    <item msgid="355508996603873860">"Connexion à <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Authentification avec <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtention de l\'adresse IP à partir de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connecté à <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendu"</item>
+    <item msgid="7698638434317271902">"Déconnexion de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Déconnecté"</item>
+    <item msgid="8578370891960825148">"Échec"</item>
+    <item msgid="5660739516542454527">"Bloqué"</item>
+    <item msgid="1805837518286731242">"Mauvaise connexion évitée momentanément"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..6760af6
--- /dev/null
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossible de rechercher des réseaux."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Aucun"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Enregistré"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Désactivés"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Échec de configuration de l\'adresse IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de connexion Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
+    <string name="saved_network" msgid="4352716707126620811">"Enregistrés par <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté à l\'aide de l\'assistant Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté par %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Accessible par %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connecté, aucun accès à Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Déconnecté"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Déconnexion…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connexion en cours…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connecté"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Association…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connecté (sans audio pour appels tél.)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connecté (sans audio contenu mutimédia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connecté (sans accès aux messages)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connecté (sans audio tel./multimédia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Paramètres audio du support"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Paramètres audio du téléphone"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfert de fichier"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Périphérique d\'entrée"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Accès Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Partage de contact"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utiliser pour le partage de contacts"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Partage de connexion Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Accès aux messages"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accès à la carte SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connecté aux paramètres audio du média"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connecté à l\'audio du téléphone"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connexion au serveur de transfert de fichiers"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connecté à la carte"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connecté au point d\'accès au service"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Connexion au serveur de transfert de fichiers non établie"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connecté au périphérique d\'entrée"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connecté à l\'appareil pour accès Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connexion Internet locale partagée"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utiliser pour l\'accès à Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utiliser pour la carte"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utiliser pour l\'accès à la carte SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utiliser pour les paramètres audio du support"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utiliser pour les paramètres audio du téléphone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utiliser pour le transfert de fichiers"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utiliser comme entrée"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Associer"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ASSOCIER"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuler"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"L\'association vous permet d\'accéder à vos contacts et à l\'historique des appels lorsque vous êtes connecté."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Impossible d\'associer à <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Impossible d\'établir l\'association avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g> en raison d\'un NIP ou d\'une clé d\'accès incorrects."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Impossible d\'établir la communication avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Association refusée par <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi désactivé."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi déconnecté."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi : une barre."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi : deux barres."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi : trois barres."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi : signal complet."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Système d\'exploitation Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applications supprimées"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Applications et utilisateurs supprimés"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Partage de connexion par USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Point d\'accès Wi-Fi mobile"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Via Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Partage de connexion"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Partage de connexion et point d\'accès mobile"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil professionnel"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Invité"</string>
+    <string name="unknown" msgid="1592123443519355854">"Inconnu"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Utilisateur : <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Certaines préférences par défaut définies"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Aucune préférence par défaut définie"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-fr/arrays.xml b/packages/SettingsLib/res/values-fr/arrays.xml
new file mode 100644
index 0000000..050793b
--- /dev/null
+++ b/packages/SettingsLib/res/values-fr/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Recherche…"</item>
+    <item msgid="8513729475867537913">"Connexion…"</item>
+    <item msgid="515055375277271756">"Authentification..."</item>
+    <item msgid="1943354004029184381">"Récupération de l\'adresse IP…"</item>
+    <item msgid="4221763391123233270">"Connecté"</item>
+    <item msgid="624838831631122137">"Interrompu"</item>
+    <item msgid="7979680559596111948">"Déconnexion…"</item>
+    <item msgid="1634960474403853625">"Déconnecté"</item>
+    <item msgid="746097431216080650">"Échec"</item>
+    <item msgid="6367044185730295334">"Bloqué"</item>
+    <item msgid="503942654197908005">"Mauvaise connexion évitée momentanément"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Recherche…"</item>
+    <item msgid="355508996603873860">"Connexion à <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Authentification avec <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Récupération de l\'adresse IP à partir de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Connecté à <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Interrompu"</item>
+    <item msgid="7698638434317271902">"Déconnexion de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Déconnecté"</item>
+    <item msgid="8578370891960825148">"Échec"</item>
+    <item msgid="5660739516542454527">"Bloqué"</item>
+    <item msgid="1805837518286731242">"Mauvaise connexion évitée momentanément"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
new file mode 100644
index 0000000..fff50c9
--- /dev/null
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossible de rechercher des réseaux."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Aucune"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Enregistré"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Désactivé"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Échec de configuration de l\'adresse IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Échec de la connexion Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problème d\'authentification."</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Hors de portée"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Aucun accès à Internet détecté, reconnexion automatique impossible"</string>
+    <string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connecté via l\'assistant Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connecté, aucun accès à Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Déconnecté"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Déconnexion…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connexion…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connecté"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Association…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Connecté (sans audio pour appels tél.)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Connecté (sans audio contenu mutimédia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connecté (sans accès aux messages)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Connecté (sans audio tel./multimédia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Multimédia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Appels et notifications"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfert de fichier"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Périphérique d\'entrée"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Accès Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Partage de contacts"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utiliser pour le partage de contacts"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Partage de connexion Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Accès aux messages"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accès à la carte SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Connecté aux paramètres audio du média"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Connecté aux paramètres audio du téléphone"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Connexion au serveur de transfert de fichiers"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connecté à la carte"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Connecté au point d\'accès au service"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Connexion au serveur de transfert de fichiers non établie"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connecté au périphérique d\'entrée"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connecté à l\'appareil pour accès Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connexion Internet locale partagée"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utiliser pour l\'accès à Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utiliser pour la carte"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utiliser pour l\'accès à la carte SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utiliser pour les paramètres audio du média"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utiliser pour les paramètres audio du téléphone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utiliser pour le transfert de fichiers"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utiliser comme entrée"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Associer"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ASSOCIER"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuler"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"L\'association vous permet d\'accéder à vos contacts et à l\'historique des appels lorsque vous êtes connecté."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Impossible d\'associer à <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Impossible d\'établir l\'association avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g> en raison d\'un code ou d\'une clé d\'accès incorrects."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Impossible d\'établir la communication avec <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Association refusée par <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi désactivé"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi déconnecté"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Signal Wi-Fi faible"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Signal Wi-Fi moyen"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Signal Wi-Fi bon"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Signal Wi-Fi excellent"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Plate-forme Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applications supprimées"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Applications et utilisateurs supprimés"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Partage connexion Bluetooth par USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Point d\'accès Wi-Fi mobile"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Partage connexion Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Partage de connexion"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Partage de connexion"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil professionnel"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Invité"</string>
+    <string name="unknown" msgid="1592123443519355854">"Inconnu"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Utilisateur : <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Certains paramètres par défaut définis"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Aucun paramètre par défaut défini"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/arrays.xml b/packages/SettingsLib/res/values-gl-rES/arrays.xml
new file mode 100644
index 0000000..8122efb
--- /dev/null
+++ b/packages/SettingsLib/res/values-gl-rES/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Buscando..."</item>
+    <item msgid="8513729475867537913">"Conectando..."</item>
+    <item msgid="515055375277271756">"Autenticando…"</item>
+    <item msgid="1943354004029184381">"Obtendo enderezo IP..."</item>
+    <item msgid="4221763391123233270">"Conectada"</item>
+    <item msgid="624838831631122137">"Suspendida"</item>
+    <item msgid="7979680559596111948">"Desconectando..."</item>
+    <item msgid="1634960474403853625">"Desconectada"</item>
+    <item msgid="746097431216080650">"Incorrecta"</item>
+    <item msgid="6367044185730295334">"Bloqueada"</item>
+    <item msgid="503942654197908005">"Evitando conexión deficiente temporalmente"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Buscando..."</item>
+    <item msgid="355508996603873860">"Conectando con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autenticando con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtendo enderezo IP de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendida"</item>
+    <item msgid="7698638434317271902">"Desconectando de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desconectada"</item>
+    <item msgid="8578370891960825148">"Incorrecta"</item>
+    <item msgid="5660739516542454527">"Bloqueada"</item>
+    <item msgid="1805837518286731242">"Evitando conexión deficiente temporalmente"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
new file mode 100644
index 0000000..ec0e5cb
--- /dev/null
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Non se poden explorar redes"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ningunha"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Gardada"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desactivadas"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Erro na configuración de IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Erro na conexión wifi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticación"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Non está dentro da zona de cobertura"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Non se detectou acceso a Internet e non se volverá conectar automaticamente."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Redes gardadas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado ao asistente de wifi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado a través de %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Dispoñible a través de %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectado, pero sen Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Conectando..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Sincronizando..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectado (ningún teléfono)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sen ficheiros multimedia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sen acceso ás mensaxes)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (ningún teléfono nin soporte)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimedia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio do teléfono"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferencia de ficheiros"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acceso a Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartir contactos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utilizar para compartir contactos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Uso compartido da conexión a Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acceso ás mensaxes"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acceso á SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao audio multimedia"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao audio do teléfono"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferencia de ficheiros"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectado ao mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Non conectado co servidor de transferencia de ficheiros"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acceder a Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compartindo conexión a Internet co dispositivo"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilízase para o acceso a Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para o mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Usar para acceso á SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilízase para audio multimedia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilízase para o audio do teléfono"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilízase para a transferencia de ficheiros"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilízase para a entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sincronizar"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"A sincronización garante acceso aos teus contactos e ao historial de chamadas ao estar conectado"</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Non se puido sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Non se puido sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que se introduciu un contrasinal ou PIN incorrecto."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Non se pode comunicar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Sincronización rexeitada por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi desactivada."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi desconectada."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Unha barra de wifi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dúas barras de wifi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tres barras de wifi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Sinal completo de wifi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicacións eliminadas"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicacións e usuarios eliminados"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ancoraxe de USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona interactiva portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ancoraxe de Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Ancoraxe á rede"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Ancoraxe á rede e zona wifi"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil do traballo"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Convidado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Descoñecida"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuario: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Definíronse algúns valores predeterminados"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Non se definiu ningún valor predeterminado"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/arrays.xml b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
new file mode 100644
index 0000000..0c9e673
--- /dev/null
+++ b/packages/SettingsLib/res/values-gu-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"કનેક્ટ થઈ રહ્યું છે…"</item>
+    <item msgid="515055375277271756">"પ્રમાણિત કરી રહ્યું છે..."</item>
+    <item msgid="1943354004029184381">"IP સરનામું મેળવી રહ્યું છે..."</item>
+    <item msgid="4221763391123233270">"કનેક્ટ કર્યું"</item>
+    <item msgid="624838831631122137">"સસ્પેન્ડ કરેલ"</item>
+    <item msgid="7979680559596111948">"ડિસ્કનેક્ટ થઈ રહ્યું છે..."</item>
+    <item msgid="1634960474403853625">"ડિસ્કનેક્ટ કર્યું"</item>
+    <item msgid="746097431216080650">"અસફળ"</item>
+    <item msgid="6367044185730295334">"અવરોધિત"</item>
+    <item msgid="503942654197908005">"નબળા કનેક્શનને અસ્થાયી રૂપે ટાળી રહ્યું છે"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> સાથે કનેક્ટ થયાં"</item>
+    <item msgid="1330262655415760617">"સસ્પેન્ડ કરેલ"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> થી ડિસ્કનેક્ટ થઈ રહ્યાં છે…"</item>
+    <item msgid="197508606402264311">"ડિસ્કનેક્ટ કર્યું"</item>
+    <item msgid="8578370891960825148">"અસફળ"</item>
+    <item msgid="5660739516542454527">"અવરોધિત"</item>
+    <item msgid="1805837518286731242">"અસ્થાયી રૂપે નબળા કનેક્શનને ટાળી રહ્યું છે"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
new file mode 100644
index 0000000..0fcf219
--- /dev/null
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"નેટવર્ક્સ માટે સ્કૅન કરી શકતા નથી"</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_network_failure" msgid="2364951338436007124">"IP કન્ફિગરેશન નિષ્ફળ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi કનેક્શન નિષ્ફળ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"પ્રમાણીકરણ સમસ્યા"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"રેન્જમાં નથી"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"કોઈ ઇન્ટરનેટ અ‍ૅક્સેસ શોધાયું નથી, આપમેળે ફરીથી કનેક્ટ કરશે નહીં."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા સચવાયું"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi સહાયક દ્વારા કનેક્ટ થયું"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s દ્વારા કનેક્ટ થયેલ"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s દ્વારા ઉપલબ્ધ"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ડિસ્કનેક્ટ કર્યું"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ડિસ્કનેક્ટ થઈ રહ્યું છે..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"કનેક્ટ થઈ રહ્યું છે…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"કનેક્ટ કર્યું"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"જોડી કરી રહ્યું છે…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"કનેક્ટ કર્યું (કોઇ ફોન નથી)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"કનેક્ટ કર્યું (મીડિયા નથી)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"કનેક્ટ કર્યું (કોઇ સંદેશ ઍક્સેસ નથી)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"કનેક્ટ કરેલ (કોઈ ફોન અથવા મીડિયા નથી)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"મીડિયા ઑડિઓ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ફોન ઑડિઓ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ફાઇલ સ્થાનાંતરણ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ઇનપુટ ઉપકરણ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ઇન્ટરનેટ ઍક્સેસ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"સંપર્ક શેરિંગ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"સંપર્ક શેરિંગ માટે ઉપયોગ કરો"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ઇન્ટરનેટ કનેક્શન શેરિંગ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"સંદેશ ઍક્સેસ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ઍક્સેસ"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"મીડિયા ઑડિઓ સાથે કનેક્ટ કર્યુ"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ફોન ઑડિઓ સાથે કનેક્ટ થયાં"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયાં"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"નકશા સાથે કનેક્ટ થયું"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP થી કનેક્ટ કરેલ"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ફાઇલ સ્થાનાંતરણ સેવાથી કનેક્ટ થયેલ નથી"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ઇનપુટ ઉપકરણ સાથે કનેક્ટ થયાં"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપકરણથી કનેક્ટેડ છે"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ઉપકરણ સાથે સ્થાનિક ઇન્ટરનેટ કનેક્શન શેર કરે છે"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ઇન્ટરનેટ ઍક્સેસ માટે ઉપયોગ કરો"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"નકશા માટે વાપરો"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ઍક્સેસ માટે ઉપયોગ કરો"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"મીડિયા ઑડિઓ માટે ઉપયોગ કરો"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ફોન ઑડિઓ માટે ઉપયોગ કરો"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ફાઇલ સ્થાનાંતર માટે ઉપયોગ કરો"</string>
+    <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_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">"એક ખોટા PIN અથવા પાસકીને કારણે <xliff:g id="DEVICE_NAME">%1$s</xliff:g> સાથે જોડી બનાવી શકાઈ નથી."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> સાથે સંચાર કરી શકાતો નથી."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> દ્વારા જોડી કરવાનું નકાર્યું."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi બંધ."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi ડિસ્કનેક્ટ થયું."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi એક બાર."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi બે બાર."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi ત્રણ બાર."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"પૂર્ણ Wifi સિગ્નલ."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"દૂર કરેલી એપ્લિકેશનો"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"દૂર કરેલી એપ્લિકેશનો અને વપરાશકર્તાઓ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ટિથરિંગ"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"પોર્ટેબલ હોટસ્પોટ"</string>
+    <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="8101244883654409696">"કાર્ય પ્રોફાઇલ"</string>
+    <string name="user_guest" msgid="8475274842845401871">"અતિથિ"</string>
+    <string name="unknown" msgid="1592123443519355854">"અજાણ્યું"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"વપરાશકર્તા: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-hi/arrays.xml b/packages/SettingsLib/res/values-hi/arrays.xml
new file mode 100644
index 0000000..ec1c57f
--- /dev/null
+++ b/packages/SettingsLib/res/values-hi/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"कनेक्ट हो रहा है..."</item>
+    <item msgid="515055375277271756">"प्रमाणीकरण कर रहा है…"</item>
+    <item msgid="1943354004029184381">"IP पता प्राप्त कर रहा है…"</item>
+    <item msgid="4221763391123233270">"कनेक्ट किया गया"</item>
+    <item msgid="624838831631122137">"निलंबित"</item>
+    <item msgid="7979680559596111948">"डिस्‍कनेक्‍ट हो रहा है..."</item>
+    <item msgid="1634960474403853625">"डिस्कनेक्‍ट किया गया"</item>
+    <item msgid="746097431216080650">"असफल"</item>
+    <item msgid="6367044185730295334">"अवरोधित"</item>
+    <item msgid="503942654197908005">"खराब कनेक्शन को अस्थायी रूप से अनदेखा कर रहा है"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> से कनेक्‍ट किया गया"</item>
+    <item msgid="1330262655415760617">"निलंबित"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> से डिस्‍कनेक्‍ट कर रहा है…"</item>
+    <item msgid="197508606402264311">"डिस्कनेक्‍ट किया गया"</item>
+    <item msgid="8578370891960825148">"असफल"</item>
+    <item msgid="5660739516542454527">"अवरोधित"</item>
+    <item msgid="1805837518286731242">"खराब कनेक्शन को अस्थायी रूप से अनदेखा कर रहा है"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
new file mode 100644
index 0000000..8d5a16b
--- /dev/null
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्क के लिए स्‍कैन नहीं कर सकता"</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_network_failure" msgid="2364951338436007124">"IP कॉन्‍फ़िगरेशन की विफलता"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफ़ाई कनेक्‍शन विफलता"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"रेंज में नहीं"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"किसी इंटरनेट कनेक्‍शन का पता नहीं चला, अपने आप पुन: कनेक्‍ट नहीं हो सकता."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> के द्वारा सहेजा गया"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"वाई-फ़ाई सहायक के द्वारा कनेक्‍ट है"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s के द्वारा उपलब्ध"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s के द्वारा उपलब्ध"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"कनेक्ट किया गया, इंटरनेट नहीं"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"डिस्कनेक्‍ट किया गया"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्‍कनेक्‍ट हो रहा है..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट हो रहा है..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"कनेक्ट किया गया"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"युग्‍मित कर रहा है…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"कनेक्‍ट है (फ़ोन नहीं)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"कनेक्‍ट है (मीडि‍या नहीं)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"कनेक्ट किया गया (कोई संदेश एक्सेस नहीं)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"कनेक्‍ट है (फ़ोन या मीडि‍या नहीं)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मीडिया ऑडियो"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"फ़ोन ऑडियो"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"फ़ाइल स्थानांतरण"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"इनपुट डिवाइस"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"इंटरनेट पहुंच"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"संपर्क साझाकरण"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"संपर्क साझाकरण के लिए उपयोग करें"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इंटरनेट कनेक्शन साझाकरण"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"संदेश एक्सेस"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम ऐक्सेस"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मीडिया ऑडियो से कनेक्‍ट किया गया"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फ़ोन ऑडियो से कनेक्‍ट किया गया"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फ़ाइल स्‍थानांतरण सर्वर से कनेक्‍ट किया गया"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"मानचित्र से कनेक्ट किया गया"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP से कनेक्ट किया गया"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फ़ाइल स्‍थानांतरण सर्वर से कनेक्‍ट नहीं किया गया"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिवाइस से कनेक्‍ट किया गया"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इंटरनेट पहुंच के लिए डिवाइस से कनेक्‍ट"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"डिवाइस से स्‍थानीय इंटरनेट कनेक्‍शन शेयर किया जा रहा है"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इंटरनेट पहुंच के लिए उपयोग करें"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"मानचित्र के लिए उपयोग करें"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"सिम ऐक्सेस के लिए उपयोग करें"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडियो के लिए उपयोग करें"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फ़ोन ऑडियो के लिए उपयोग करें"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फ़ाइल स्‍थानांतरण के लिए उपयोग करें"</string>
+    <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_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> के साथ युग्‍मित नहीं हो सका."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> से संचार नहीं कर सकता."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारा युग्‍मन अस्‍वीकृत किया गया."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"वाई-फ़ाई बंद है."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"वाई-फ़ाई डिस्कनेक्ट है."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"वाई-फ़ाई का एक बार है."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"वाई-फ़ाई की दो पट्टी मिल रही हैं."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"वाई-फ़ाई की एक पट्टी मिल रही है."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"पूरे वाई-फ़ाई सिग्नल मिल रहे हैं."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"निकाले गए ऐप्स"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ऐप्स  और उपयोगकर्ताओं को निकालें"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेदरिंग"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्‍पॉट"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटूथ टेदरिंग"</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="8101244883654409696">"कार्य प्रोफ़ाइल"</string>
+    <string name="user_guest" msgid="8475274842845401871">"अतिथि"</string>
+    <string name="unknown" msgid="1592123443519355854">"अज्ञात"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"उपयोगकर्ता: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
new file mode 100644
index 0000000..b7a0d51
--- /dev/null
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skeniranje..."</item>
+    <item msgid="8513729475867537913">"Povezivanje…"</item>
+    <item msgid="515055375277271756">"Autentikacija…"</item>
+    <item msgid="1943354004029184381">"Dohvaćanje IP adrese…"</item>
+    <item msgid="4221763391123233270">"Povezan"</item>
+    <item msgid="624838831631122137">"Obustavljeno"</item>
+    <item msgid="7979680559596111948">"Isključivanje…"</item>
+    <item msgid="1634960474403853625">"Niste povezani"</item>
+    <item msgid="746097431216080650">"Neuspješno"</item>
+    <item msgid="6367044185730295334">"Blokirano"</item>
+    <item msgid="503942654197908005">"Privremeno izbjegavanje loše veze"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skeniranje..."</item>
+    <item msgid="355508996603873860">"Povezivanje na mrežu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autentikacija s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Dohvaćanje IP adrese s mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Povezano s mrežom <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Obustavljeno"</item>
+    <item msgid="7698638434317271902">"Isključivanje iz mreže <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Niste povezani"</item>
+    <item msgid="8578370891960825148">"Neuspješno"</item>
+    <item msgid="5660739516542454527">"Blokirano"</item>
+    <item msgid="1805837518286731242">"Privremeno izbjegavanje loše veze"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
new file mode 100644
index 0000000..e497d3a
--- /dev/null
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Skeniranje mreža nije moguće"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nema"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Spremljeno"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogućeno"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Konfiguracija IP-a nije uspjela"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezivanje s Wi-Fi-jem nije uspjelo"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem u autentifikaciji"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Nije u rasponu"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Pristup internetu nije otkriven. Nema automatskog ponovnog povezivanja."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Spremljeno: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Povezani putem pomoćnika za Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Povezano putem %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Dostupno putem %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Povezano, bez interneta"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Niste povezani"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Isključivanje…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Povezivanje…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Povezan"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Uparivanje…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Povezano (bez telefona)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezano (bez medija)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezano (bez pristupa porukama)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezano (bez telefona ili medija)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medijski zvuk"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefona"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prijenos datoteke"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ulazni uređaj"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Pristup internetu"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Dijeljenje kontakata"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Upotrijebi za dijeljenje kontakata"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Dijeljenje internetske veze"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Pristup porukama"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Pristup SIM-u"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezano s medijskim zvukom"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezano sa telefonskim zvukom"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezano s poslužiteljem za prijenos datoteka"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezano s kartom"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Povezano sa SAP-om"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Niste povezani s poslužiteljem za prijenos datoteka"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezano s ulaznim uređajem"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povezano s uređajem za pristup internetu"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dijeljenje lokalne internetske veze s uređajem"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Upotrijebi za pristup internetu"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Upotreba za kartu"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Upotrijebi za pristup SIM-u"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Koristi za medijski zvuk"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Koristi za telefonski zvuk"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Koristi za prijenos datoteke"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Upotrijebi za ulaz"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Upari"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"UPARI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Odustani"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Uparivanje omogućuje pristup vašim kontaktima i povijesti poziva dok ste povezani."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Uparivanje s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije bilo moguće."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Uparivanje s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije bilo moguće zbog netočnog PIN-a ili zaporke."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Komunikacija s uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nije moguća."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Uparivanje odbio uređaj <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je isključen."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi je isključen."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi signal ima jedan stupac."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi signal ima dva stupca."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi signal ima tri stupca."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi signal je pun."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Uklonjene aplikacije"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Uklonjene aplikacije i korisnici"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB dijeljenje veze"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prijen. pristupna točka"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Dijeljenje Bluetoothom veze"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Dijeljenje veze"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Dijeljenje veze i žarišna točka"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Radni profil"</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>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Postavljene su neke zadane postavke"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nema zadanih postavki"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-hu/arrays.xml b/packages/SettingsLib/res/values-hu/arrays.xml
new file mode 100644
index 0000000..681489e
--- /dev/null
+++ b/packages/SettingsLib/res/values-hu/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Keresés..."</item>
+    <item msgid="8513729475867537913">"Kapcsolódás…"</item>
+    <item msgid="515055375277271756">"Hitelesítés..."</item>
+    <item msgid="1943354004029184381">"IP-cím lekérése..."</item>
+    <item msgid="4221763391123233270">"Csatlakozva"</item>
+    <item msgid="624838831631122137">"Felfüggesztve"</item>
+    <item msgid="7979680559596111948">"Kapcsolat bontása..."</item>
+    <item msgid="1634960474403853625">"Nincs kapcsolat"</item>
+    <item msgid="746097431216080650">"Sikertelen"</item>
+    <item msgid="6367044185730295334">"Letiltva"</item>
+    <item msgid="503942654197908005">"A rossz minőségű kapcsolatok átmeneti elkerülése"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Keresés..."</item>
+    <item msgid="355508996603873860">"Csatlakozás a(z) <xliff:g id="NETWORK_NAME">%1$s</xliff:g> hálózathoz..."</item>
+    <item msgid="554971459996405634">"Hitelesítés a(z) <xliff:g id="NETWORK_NAME">%1$s</xliff:g> hálózaton..."</item>
+    <item msgid="7928343808033020343">"IP-cím lekérése a(z) <xliff:g id="NETWORK_NAME">%1$s</xliff:g> hálózattól..."</item>
+    <item msgid="8937994881315223448">"Kapcsolódva a(z) <xliff:g id="NETWORK_NAME">%1$s</xliff:g> hálózathoz"</item>
+    <item msgid="1330262655415760617">"Felfüggesztve"</item>
+    <item msgid="7698638434317271902">"Kapcsolat bontása <xliff:g id="NETWORK_NAME">%1$s</xliff:g> hálózattal..."</item>
+    <item msgid="197508606402264311">"Nincs kapcsolat"</item>
+    <item msgid="8578370891960825148">"Sikertelen"</item>
+    <item msgid="5660739516542454527">"Letiltva"</item>
+    <item msgid="1805837518286731242">"A rossz minőségű kapcsolatok átmeneti elkerülése"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
new file mode 100644
index 0000000..aefc45f
--- /dev/null
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nem lehet beolvasni a hálózatokat"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nincs"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Mentve"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Letiltva"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurációs hiba"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-kapcsolati hiba"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Azonosítási probléma"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Hatókörön kívül"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nincs érzékelhető internet-hozzáférés, ezért nem kapcsolódik újra automatikusan."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Mentette: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Csatlakozva Wi‑Fi-segéddel"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Csatlakozva a következőn keresztül: %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Elérhető a következőn keresztül: %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Csatlakozva, nincs internetelérés"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Szétkapcsolva"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Szétkapcsolás..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Csatlakozás…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Csatlakozva"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Párosítás..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Csatlakoztatva (nincs telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Csatlakoztatva (nincs hordozó)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Csatlakoztatva (nincs üzenet-hozzáférés)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Csatlakoztatva (nincs telefon vagy hordozó)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Média audió"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefon hangja"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fájlátvitel"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Beviteli eszköz"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetelérés"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Névjegyek megosztása"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Használja a névjegyek megosztására"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internetkapcsolat megosztása"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Üzenet-hozzáférés"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-elérés"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Csatlakoztatva az eszköz hangjához"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Csatlakoztatva a telefon hangjához"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Csatlakozva a fájlküldő szerverhez"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Csatlakoztatva a térképhez"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Csatlakozva az SAP-hoz"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nincs csatlakozva a fájlküldő szerverhez"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Beviteli eszköz csatlakoztatva"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Eszközhöz csatlakozik az interneteléréshez"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Helyi internetkapcsolat megosztva az eszközzel"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Használat internetelérésre"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Használat a térképhez"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Használat SIM-elérésre"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Felhasználás az eszköz hangjához"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Felhasználás a telefon hangjához"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Felhasználás fájlátvitelre"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Használat beviteli eszközként"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párosítás"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROSÍTÁS"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Mégse"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"A párosítás hozzáférést biztosít a névjegyekhez és híváselőzményekhez összekapcsolt állapotban."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nem lehet párosítani a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközzel."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"A párosítás sikertelen volt a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközzel hibás PIN kód vagy jelszó miatt."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nem lehet kommunikálni a(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszközzel."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"A(z) <xliff:g id="DEVICE_NAME">%1$s</xliff:g> eszköz elutasította a párosítást."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi kikapcsolva."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Nincs Wi-Fi-kapcsolat."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-jel: egy sáv."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi-jel: két sáv."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi-jel: három sáv."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi-jel: teljes."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Eltávolított alkalmazások"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Eltávolított alkalmazások és felhasználók"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-megosztás"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hordozható hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth megosztása"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Megosztás"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Megosztás és hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Munkaprofil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Vendég"</string>
+    <string name="unknown" msgid="1592123443519355854">"Ismeretlen"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Felhasználó: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Van néhány alapbeállítás"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nincs alapbeállítás"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/arrays.xml b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
new file mode 100644
index 0000000..483e9d3
--- /dev/null
+++ b/packages/SettingsLib/res/values-hy-rAM/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Միանում է..."</item>
+    <item msgid="515055375277271756">"Նույնականացում…"</item>
+    <item msgid="1943354004029184381">"IP հասցեն գտնվում է...."</item>
+    <item msgid="4221763391123233270">"Միացված է"</item>
+    <item msgid="624838831631122137">"Կասեցված է"</item>
+    <item msgid="7979680559596111948">"Անջատվում է…"</item>
+    <item msgid="1634960474403853625">"Անջատված է"</item>
+    <item msgid="746097431216080650">"Անհաջող"</item>
+    <item msgid="6367044185730295334">"Արգելափակված"</item>
+    <item msgid="503942654197908005">"Ժամանակավորապես խուսափելով թույլ կապից"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"IP հասցեի ստացում <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ից…"</item>
+    <item msgid="8937994881315223448">"Միացված է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ին"</item>
+    <item msgid="1330262655415760617">"Անջատված"</item>
+    <item msgid="7698638434317271902">"Անջատվում է <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-ից…"</item>
+    <item msgid="197508606402264311">"Անջատված"</item>
+    <item msgid="8578370891960825148">"Անհաջող"</item>
+    <item msgid="5660739516542454527">"Արգելափակված"</item>
+    <item msgid="1805837518286731242">"Վատ ցանցից ժամանակավոր խուսափում"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
new file mode 100644
index 0000000..7df405a
--- /dev/null
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Հնարավոր չէ սկանավորել ցանցերը"</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_network_failure" msgid="2364951338436007124">"IP կարգավորման ձախողում"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi կապի ձախողում"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Նույնականացման խնդիր"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ընդգրկույթից դուրս է"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ինտերնետի հասանելիություն չկա. ավտոմատ կերպով կրկին չի միանա:"</string>
+    <string name="saved_network" msgid="4352716707126620811">"Պահել է հետևյալ օգտվողը՝ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Կապակցված է Wi‑Fi Օգնականի միջոցով"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Կապակցված է %1$s-ի միջոցով"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Հասանելի է %1$s-ի միջոցով"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Կապակցված է առանց համացանցի"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Անջատված է"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Անջատվում է..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Միանում է..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Միացված է"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Զուգավորում..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Միացված (առանց հեռախոսի)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Միացված է (առանց մեդիա)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Միացված է (հաղորդագրությանը մուտք չկա)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Միացված է (առանց հեռախոսի և մեդիայի)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Մեդիա աուդիո"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Հեռախոսի աուդիո"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Ֆայլերի փոխանցում"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ներմուծման սարք"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Ինտերնետի մուտք"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Կոնտակտի համօգտագործում"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Օգտագործել կոնտակտի համօգտագործման համար"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Ինտերնետ կապի տարածում"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Մուտք հաղորդագրություն"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM քարտի հասանելիություն"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Միացված է մեդիա աուդիոյին"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Միացված է հեռախոսի ձայնային տվյալներին"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Միացված է ֆայլերի փոխանցման սերվերին"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Միացված է քարտեզին"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Կապակցված է SAP-ին"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ֆայլերը փոխանցող սերվերի հետ կապ չկա"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Միացված է մուտքային սարքին"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Կապակցված է սարքին` ինտերնետ մուտք գործելու համար"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Տեղային ինտերնետ կապի տարածում սարքի հետ"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Օգտագործել ինտերնետ մուտք գործելու համար"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Օգտագործել քարտեզի համար"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM քարտի օգտագործում"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Օգտագործել մեդիա աուդիոյի համար"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Օգտագործել հեռախոսի աուդիոյի համար"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Օգտագործել ֆայլի փոխանցման համար"</string>
+    <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_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-ի կամ անցաբառի պատճառով:."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Հնարավոր չէ կապ հաստատել  <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի հետ:"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Զուգավորումը մերժվեց <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ի կողմից:"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi-ն անջատված է:"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi-ը կապակցված չէ:"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-ի ուժգնությունը՝ մեկ գիծ:"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi-ի ուժգնությունը՝ երկու գիծ:"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi-ի ուժգնությունը՝ երեք գիծ:"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi-ի ազդանշանը ուժեղ է:"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Հեռացված ծրագրեր"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Հեռացված հավելվածներն ու օգտվողները"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB միացում"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Դյուրակիր թեժ կետ"</string>
+    <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="8101244883654409696">"Աշխատանքային պրոֆիլ"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Հյուր"</string>
+    <string name="unknown" msgid="1592123443519355854">"Անհայտ"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Օգտվող՝ <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
new file mode 100644
index 0000000..c2488df
--- /dev/null
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Memindai..."</item>
+    <item msgid="8513729475867537913">"Menyambung…"</item>
+    <item msgid="515055375277271756">"Mengautentikasi…"</item>
+    <item msgid="1943354004029184381">"Mendapatkan alamat IP…"</item>
+    <item msgid="4221763391123233270">"Terhubung"</item>
+    <item msgid="624838831631122137">"Ditangguhkan"</item>
+    <item msgid="7979680559596111948">"Memutus sambungan..."</item>
+    <item msgid="1634960474403853625">"Sambungan terputus"</item>
+    <item msgid="746097431216080650">"Gagal"</item>
+    <item msgid="6367044185730295334">"Dicekal"</item>
+    <item msgid="503942654197908005">"Menghindari sambungan buruk untuk sementara"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Memindai..."</item>
+    <item msgid="355508996603873860">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Tersambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Ditangguhkan"</item>
+    <item msgid="7698638434317271902">"Diputus dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Sambungan terputus"</item>
+    <item msgid="8578370891960825148">"Gagal"</item>
+    <item msgid="5660739516542454527">"Dicekal"</item>
+    <item msgid="1805837518286731242">"Menghindari sambungan buruk untuk sementara"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
new file mode 100644
index 0000000..32dfa03
--- /dev/null
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak dapat memindai jaringan"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Tidak Ada"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Nonaktif"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah autentikasi"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam jangkauan"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Akses Internet Tidak Terdeteksi, tidak akan menyambung ulang secara otomatis."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Terhubung melalui Asisten Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Terhubung melalui %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tersambung, tidak ada internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Sambungan terputus"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Memutus sambungan..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Menyambung…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Terhubung"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Menyandingkan..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Terhubung (bukan telepon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Terhubung (kecuali media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tersambung (tidak ada akses pesan)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Terhubung (bukan telepon atau media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio media"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio telepon"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfer file"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Perangkat masukan"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Akses Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Berbagi kontak"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Gunakan untuk berbagi kontak"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Berbagi sambungan internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Akses Pesan"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Akses SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Tersambung ke media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Tersambung ke audio ponsel"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Sambungkan ke server transfer file"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Tersambung ke peta"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Terhubung ke SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Tidak tersambung kepada server transfer file"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Terhubung ke perangkat masukan"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tersambung ke perangkat untuk akses Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Berbagi sambungan Internet lokal dengan perangkat"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Digunakan untuk akses internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gunakan untuk peta"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gunakan untuk akses SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gunakan untuk audio media"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gunakan untuk audio ponsel"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gunakan untuk transfer file"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gunakan untuk masukan"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sandingkan"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SANDINGKAN"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Penyandingan memberi akses ke kontak dan riwayat panggilan saat tersambung"</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Tidak dapat menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Tidak dapat menyandingkan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> karena PIN atau kode sandi salah."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Tidak dapat berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Penyandingan ditolak oleh <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi tidak aktif."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi tidak tersambung."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi satu baris."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi dua baris"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi tiga baris."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Sinyal Wi-Fi penuh."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplikasi dihapus"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplikasi dan pengguna yang dihapus"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Penambatan USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabel"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Penambatan bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Menambatkan"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Menambatkan &amp; hotspot portabel"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil kerja"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Tamu"</string>
+    <string name="unknown" msgid="1592123443519355854">"Tidak diketahui"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Pengguna: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Beberapa setelan default"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Tidak ada setelan default"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/arrays.xml b/packages/SettingsLib/res/values-is-rIS/arrays.xml
new file mode 100644
index 0000000..540956f
--- /dev/null
+++ b/packages/SettingsLib/res/values-is-rIS/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Leitar…"</item>
+    <item msgid="8513729475867537913">"Tengist…"</item>
+    <item msgid="515055375277271756">"Auðkennir…"</item>
+    <item msgid="1943354004029184381">"Sækir IP-tölu…"</item>
+    <item msgid="4221763391123233270">"Tengt"</item>
+    <item msgid="624838831631122137">"Lokað"</item>
+    <item msgid="7979680559596111948">"Aftengist…"</item>
+    <item msgid="1634960474403853625">"Aftengt"</item>
+    <item msgid="746097431216080650">"Mistókst"</item>
+    <item msgid="6367044185730295334">"Læst"</item>
+    <item msgid="503942654197908005">"Forðast lélega tengingu tímabundið"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Leitar…"</item>
+    <item msgid="355508996603873860">"Tengist <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Auðkennir á <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Sækir IP-tölu frá <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Tengt við <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Lokað"</item>
+    <item msgid="7698638434317271902">"Aftengist <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Aftengt"</item>
+    <item msgid="8578370891960825148">"Mistókst"</item>
+    <item msgid="5660739516542454527">"Læst"</item>
+    <item msgid="1805837518286731242">"Forðast lélega tengingu tímabundið"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
new file mode 100644
index 0000000..a3dd8c4
--- /dev/null
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ekki er hægt að leita að netum"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ekkert"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Vistað"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Óvirkt"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-stillingarvilla"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi-tengingarvilla"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Vandamál við auðkenningu"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ekkert samband"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Enginn netaðgangur fannst; endurtengist ekki sjálfkrafa."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> vistaði"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Tengt í gegnum Wi-Fi aðstoð"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Tengt í gegnum %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Í boði í gegnum %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tengt, enginn internetaðgangur"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Aftengt"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Aftengist…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Tengist…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Tengt"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Parar…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Tengt (ekki sími)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tengt (ekki efnisspilun)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tengt (enginn skilaboðaaðgangur)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Tengt (ekki sími eða efnisspilun)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Hljóð efnis"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Hljóð síma"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Skráaflutningur"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inntakstæki"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetaðgangur"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Deiling tengiliða"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Nota til að deila tengiliðum"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deiling nettengingar"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Skilaboðaaðgangur"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Aðgangur að SIM-korti"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Tengt við hljóðspilun efnis"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Tengt við hljóð símans"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Tengt við skráaflutningsþjón"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Tengt við kort"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Tengt við SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ekki tengt við skráaflutningsþjón."</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Tengt við inntakstæki"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Tengt við tæki til að fá netaðgang"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Internettengingu deilt með tæki"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Nota fyrir netaðgang"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Nota fyrir kort"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Nota fyrir aðgang að SIM-korti"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Nota fyrir hljóð efnisspilunar"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Nota fyrir hljóð símans"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Nota við skráaflutning"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Nota fyrir inntak"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Para"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PARA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Hætta við"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Pörun veitir aðgang að tengiliðunum þínum og símtalaferli þegar tengingu hefur verið komið á."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Ekki var hægt að para við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ekki tókst að para við <xliff:g id="DEVICE_NAME">%1$s</xliff:g> þar sem PIN-númer eða aðgangslykill er rangur."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ekki er hægt að eiga samskipti við <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> hafnaði pörun."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Slökkt á Wi-Fi."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi ótengt."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: Eitt strik."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: Tvö strik."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: Þrjú strik."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Fullur Wi-Fi sendistyrkur."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android stýrikerfið"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjarlægð forrit"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjarlægð forrit og notendur"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-tjóðrun"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Heitur reitur"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-tjóðrun"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tjóðrun"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tjóðrun og heitur reitur"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Vinnusnið"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gestur"</string>
+    <string name="unknown" msgid="1592123443519355854">"Óþekkt"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Notandi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Einhver sjálfgildi valin"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Engin sjálfgildi valin"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-it/arrays.xml b/packages/SettingsLib/res/values-it/arrays.xml
new file mode 100644
index 0000000..719adbc
--- /dev/null
+++ b/packages/SettingsLib/res/values-it/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Ricerca..."</item>
+    <item msgid="8513729475867537913">"Connessione..."</item>
+    <item msgid="515055375277271756">"Autenticazione..."</item>
+    <item msgid="1943354004029184381">"Acquisizione indirizzo IP..."</item>
+    <item msgid="4221763391123233270">"Connessa"</item>
+    <item msgid="624838831631122137">"Sospesa"</item>
+    <item msgid="7979680559596111948">"Disconnessione..."</item>
+    <item msgid="1634960474403853625">"Disconnessa"</item>
+    <item msgid="746097431216080650">"Operazione non riuscita"</item>
+    <item msgid="6367044185730295334">"Bloccato"</item>
+    <item msgid="503942654197908005">"Al momento vengono evitate connessioni deboli"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Ricerca..."</item>
+    <item msgid="355508996603873860">"Connessione a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Autenticazione con <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Acquisizione indirizzo IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Connessa a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Sospesa"</item>
+    <item msgid="7698638434317271902">"Disconnessione da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Disconnessa"</item>
+    <item msgid="8578370891960825148">"Operazione non riuscita"</item>
+    <item msgid="5660739516542454527">"Bloccato"</item>
+    <item msgid="1805837518286731242">"Al momento vengono evitate connessioni deboli"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
new file mode 100644
index 0000000..d5b4a15
--- /dev/null
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Impossibile cercare reti"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nessuna"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Salvata"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Disattivata"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Errore configurazione IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Errore connessione Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema di autenticazione"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fuori portata"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nessun accesso a Internet rilevato, non verrà eseguita la riconnessione automatica."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Salvata da <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Connesso tramite assistente Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Collegato tramite %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibile tramite %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connesso senza Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Disconnesso"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Disconnessione..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Connessione..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Connesso"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Accoppiamento..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Collegato (telefono escluso)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Collegato (contenuti multimed. esclusi)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Connesso (nessun accesso ai messaggi)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Collegato (telef. o conten. mult. esclusi)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio multimediale"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio telefono"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Trasferimento file"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo di input"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Accesso Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Condivisione contatti"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usa per condivisione contatti"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Condivisione connessione Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Accesso ai messaggi"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Accesso alla SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Collegato ad audio media"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Collegato ad audio telefono"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Collegato al server di trasferimento file"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Connesso alla mappa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Collegato al SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Non collegato al server di trasferimento file"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Connesso a dispositivo di input"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Connesso a dispositivo per accesso Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Connessione Internet locale condivisa con dispositivo"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usa per accesso Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizza per la mappa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizza per accesso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usa per audio media"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usa per audio telefono"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usa per trasferimento file"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizza per l\'input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Accoppia"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ACCOPPIA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annulla"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"L\'accoppiamento consente l\'accesso ai tuoi contatti e alla cronologia chiamate quando i dispositivi sono connessi."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Impossibile eseguire l\'accoppiamento con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. La passkey o il PIN è errato."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Impossibile comunicare con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Accoppiamento rifiutato da <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi non attivo."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Rete Wi-Fi scollegata."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: una barra."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: due barre."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: tre barre."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Segnale Wi-Fi completo."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operativo Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Applicazioni rimosse"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"App e utenti rimossi"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portatile"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering/hotspot portatile"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profilo di lavoro"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Ospite"</string>
+    <string name="unknown" msgid="1592123443519355854">"Sconosciuta"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Utente: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Alcune opzioni predefinite impostate"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nessuna applicazione predefinita impostata"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
new file mode 100644
index 0000000..d5f3d9d
--- /dev/null
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"מתחבר ..."</item>
+    <item msgid="515055375277271756">"מאמת…"</item>
+    <item msgid="1943354004029184381">"‏משיג כתובת IP…"</item>
+    <item msgid="4221763391123233270">"מחובר"</item>
+    <item msgid="624838831631122137">"בהשעיה"</item>
+    <item msgid="7979680559596111948">"מתנתק..."</item>
+    <item msgid="1634960474403853625">"מנותק"</item>
+    <item msgid="746097431216080650">"נכשל"</item>
+    <item msgid="6367044185730295334">"חסומה"</item>
+    <item msgid="503942654197908005">"נמנע זמנית מחיבור חלש"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"‏משיג כתובת IP מ-<xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"מחובר אל <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"בהשעיה"</item>
+    <item msgid="7698638434317271902">"מתנתק מרשת <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"מנותק"</item>
+    <item msgid="8578370891960825148">"נכשל"</item>
+    <item msgid="5660739516542454527">"חסומה"</item>
+    <item msgid="1805837518286731242">"נמנע זמנית מחיבור חלש"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
new file mode 100644
index 0000000..6780d1e
--- /dev/null
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"לא ניתן לסרוק לאיתור רשתות"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"מחוץ לטווח"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"אין גישה לאינטרנט. לא יתבצע חיבור מחדש באופן אוטומטי."</string>
+    <string name="saved_network" msgid="4352716707126620811">"נשמר על ידי <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"‏מחובר באמצעות אסיסטנט ה-Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"‏מחובר דרך %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"‏זמינה דרך %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"מחובר. אין אינטרנט"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"מנותק"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"מתנתק..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"מתחבר ..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"מחובר"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"מבצע התאמה..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"מחובר (ללא טלפון)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"מחובר (ללא מדיה)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"מחובר (אין גישה להודעות)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"מחובר (ללא טלפון או מדיה)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"אודיו של מדיה"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"אודיו של טלפון"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"העברת קבצים"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"מכשיר קלט"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"גישה לאינטרנט"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"שיתוף אנשי קשר"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"השתמש עבור שיתוף אנשי קשר"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"שיתוף חיבור לאינטרנט"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"גישה להודעות"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"‏גישה ל-SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"מחובר לאודיו של מדיה"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"מחובר לאודיו של הטלפון"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"מחובר לשרת העברת קבצים"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"מחובר למפה"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"‏מחובר ל-SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"לא מחובר לשרת העברת קבצים"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"מחובר למכשיר קלט"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"מחובר למכשיר לצורך גישה לאינטרנט"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"משתף חיבור אינטרנט מקומי עם מכשיר"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"השתמש עבור גישה לאינטרנט"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"שימוש עבור מפה"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"‏השתמש לגישה של SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"השתמש עבור אודיו של מדיה"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"השתמש עבור האודיו של הטלפון"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"השתמש להעברת קבצים"</string>
+    <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_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 או סיסמה שגויים."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"לא ניתן לתקשר עם <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ההתאמה נדחתה על ידי <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"‏Wi-Fi כבוי."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"‏Wi-Fi מנותק."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"‏פס אחד של Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"‏שני פסים של Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"‏שלושה פסים של Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"‏אות Wi-Fi מלא."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"אפליקציות שהוסרו"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"אפליקציות ומשתמשים שהוסרו"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏שיתוף אינטרנט דרך USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"נקודה לשיתוף אינטרנט"</string>
+    <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="8101244883654409696">"פרופיל עבודה"</string>
+    <string name="user_guest" msgid="8475274842845401871">"אורח"</string>
+    <string name="unknown" msgid="1592123443519355854">"לא ידוע"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"משתמש: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ja/arrays.xml b/packages/SettingsLib/res/values-ja/arrays.xml
new file mode 100644
index 0000000..f9f2ae7
--- /dev/null
+++ b/packages/SettingsLib/res/values-ja/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"接続中..."</item>
+    <item msgid="515055375277271756">"認証中..."</item>
+    <item msgid="1943354004029184381">"IPアドレスを取得中..."</item>
+    <item msgid="4221763391123233270">"接続済み"</item>
+    <item msgid="624838831631122137">"保留中"</item>
+    <item msgid="7979680559596111948">"切断中..."</item>
+    <item msgid="1634960474403853625">"切断されました"</item>
+    <item msgid="746097431216080650">"失敗しました"</item>
+    <item msgid="6367044185730295334">"ブロック中"</item>
+    <item msgid="503942654197908005">"接続不良により一時的に無効"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"IPアドレスを<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から取得中..."</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>に接続しました"</item>
+    <item msgid="1330262655415760617">"保留中"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>から切断中..."</item>
+    <item msgid="197508606402264311">"切断されました"</item>
+    <item msgid="8578370891960825148">"失敗しました"</item>
+    <item msgid="5660739516542454527">"ブロック中"</item>
+    <item msgid="1805837518286731242">"接続不良により一時的に無効"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
new file mode 100644
index 0000000..ceaaf13
--- /dev/null
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ネットワークをスキャンできません"</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_network_failure" msgid="2364951338436007124">"IP設定エラー"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi接続エラー"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"認証に問題"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"圏外"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"インターネットアクセスを検出できないため、自動的に再接続されません。"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>で保存"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fiアシスタント経由で接続"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s経由で接続"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s経由で使用可能"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"接続済み、インターネットは利用できません"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"切断"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"切断中..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"接続中..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"接続"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"ペアとして設定中..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"接続済み(電話を除く)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"接続済み(メディアを除く)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"接続済み(メッセージへのアクセスなし)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"接続済み(電話/メディアを除く)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"メディアの音声"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"電話の音声"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ファイル転送"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"入力デバイス"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"インターネットアクセス"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"連絡先の共有"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"連絡先の共有に使用"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"インターネット接続の共有"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"メッセージへのアクセス"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIMアクセス"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"メディアの音声に接続"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"携帯電話の音声に接続"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ファイル転送サーバーに接続"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"地図に接続済み"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPに接続"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ファイル転送サーバーに接続しない"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"入力デバイスに接続されています"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"インターネットアクセス用に接続"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ローカルインターネット接続をデバイスと共有"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"インターネットアクセスに使用する"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"地図に使用"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIMアクセスに使用"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"メディアの音声に使用"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"携帯電話の音声に使用"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ファイル転送に使用"</string>
+    <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_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">"PINまたはパスキーが正しくないため、<xliff:g id="DEVICE_NAME">%1$s</xliff:g>をペアに設定できませんでした。"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>と通信できません。"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ペア設定が<xliff:g id="DEVICE_NAME">%1$s</xliff:g>に拒否されました。"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-FiはOFFです。"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fiが切断されました。"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fiはレベル1です。"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fiはレベル2です。"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fiはレベル3です。"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fiの電波はフルです。"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"削除したアプリケーション"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"削除されたアプリとユーザー"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USBテザリング"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ポータブルアクセスポイント"</string>
+    <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="8101244883654409696">"仕事用プロファイル"</string>
+    <string name="user_guest" msgid="8475274842845401871">"ゲスト"</string>
+    <string name="unknown" msgid="1592123443519355854">"不明"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"ユーザー: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/arrays.xml b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
new file mode 100644
index 0000000..1185d8e
--- /dev/null
+++ b/packages/SettingsLib/res/values-ka-rGE/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"დაკავშირება…"</item>
+    <item msgid="515055375277271756">"ავტორიზაცია…"</item>
+    <item msgid="1943354004029184381">"IP მისამართის მიღება…"</item>
+    <item msgid="4221763391123233270">"დაკავშირებულია"</item>
+    <item msgid="624838831631122137">"შეწყვეტილია"</item>
+    <item msgid="7979680559596111948">"კავშირის გაწყვეტა…"</item>
+    <item msgid="1634960474403853625">"არ არის ხაზზე"</item>
+    <item msgid="746097431216080650">"ვერ მოხერხდა"</item>
+    <item msgid="6367044185730295334">"დაბლოკილი"</item>
+    <item msgid="503942654197908005">"ცუდი კავშირის დროებით თავიდან აცილება"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"IP მისამართის მოპოვება <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-დან…"</item>
+    <item msgid="8937994881315223448">"დაკავშირებულია <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-თან"</item>
+    <item msgid="1330262655415760617">"შეჩერებული"</item>
+    <item msgid="7698638434317271902">"კავშირის გაწყვეტა <xliff:g id="NETWORK_NAME">%1$s</xliff:g>-თან…"</item>
+    <item msgid="197508606402264311">"კავშირი გაწყვეტილია"</item>
+    <item msgid="8578370891960825148">"ვერ მოხერხდა"</item>
+    <item msgid="5660739516542454527">"დაბლოკილი"</item>
+    <item msgid="1805837518286731242">"ცუდი კავშირის დროებით თავიდან აცილება"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
new file mode 100644
index 0000000..286c709
--- /dev/null
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ქსელების სკანირება არა არის შესაძლებელი"</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_network_failure" msgid="2364951338436007124">"IP კონფიგურაციის შეფერხება"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi კავშირის შეფერხება"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ავთენტიკაციის პრობლემა"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"არ არის დიაპაზონში"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ინტერნეტთან წვდომის ამოცნობა ვერ მოხერხდა. ავტომატურად ხელახლა დაკავშირება არ განხორციელდება."</string>
+    <string name="saved_network" msgid="4352716707126620811">"შენახული <xliff:g id="NAME">%1$s</xliff:g>-ის მიერ"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"დაკავშირებულია Wi-Fi თანაშემწით"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-ით დაკავშირებული"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"ხელმისაწვდომია %1$s-ით"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"კავშირი გაწყვეტილია"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"მიმდინარეობს გათიშვა…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"მიმდინარეობს დაკავშირება…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"შეერთებულია"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"დაწყვილება…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"დაკავშირებულია (ტელეფონის გარდა)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"მიერთებულია (მედიის გარდა)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"დაკავშირებულია (შეტყობინებაზე წვდომა არ არის)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"დაკავშირება (გარდა ტელეფონისა და მედიისა)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"მედია აუდიო"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ტელეფონის აუდიო"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ფაილების გადაცემა"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"შეყვანის მოწყობილობა"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ინტერნეტზე წვდომა"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"კონტაქტის გაზიარება"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"კონტაქტის გაზიარებისთვის გამოყენება"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ინტერნეტ კავშირის გაზიარება"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"შეტყობინებებზე წვდომა"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM წვდომა"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"დაკავშირებულია აუდიო მულტიმედიურ სისტემასთან"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"დაკავშირებულია ტელეფონის აუდიო მოწყობილობასთან"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"დაკავშირებულია ფაილების გადაცემის სერვერთან"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"რუკასთან დაკავშირებული"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-თან დაკავშირებული"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"არ არის დაკავშირებული ფაილების ტრანსფერის სერვერთან"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"დაკავშირებულია შეყვანის მოწყობილობასთან"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"დაკავშირებულია მოწყობილობასთან ინტერნეტთან წვდომისთვის"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ლოკალური კავშირის გაზიარება მოწყობილობასთან"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"გამოიყენე ინტერნეტთან წვდომისთვის"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"რუკაზე გამოყენება"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"გამოყენება SIM წვდომისთვის"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"მედია აუდიოსთვის გამოყენება"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"გამოიყენეთ ტელეფონის აუდიომოწყობილობაში"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ფაილების ტრანსფერისათვის გამოყენება"</string>
+    <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_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 ან გასაღები არასწორია."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"შეუძლებელია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-თან კომუნიკაცია."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"დაწყვილება უარყოფილია <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ის მიერ."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi გამორთულია."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"WiFi არ არის დაკავშირებული."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WiFi სიგნალი ერთ ზოლზეა."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WiFi სიგნალი ორ ზოლზეა."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WiFi სიგნალი სამ ზოლზეა."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WiFi სიგნალი სრულია."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"აპების წაშლა"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"წაშლილი აპები და მომხმარებლები"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB მოდემი"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"პორტატული უსადენო ქსელი"</string>
+    <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="8101244883654409696">"სამუშაო პროფილი"</string>
+    <string name="user_guest" msgid="8475274842845401871">"სტუმარი"</string>
+    <string name="unknown" msgid="1592123443519355854">"უცნობი"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"მომხმარებელი: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/arrays.xml b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
new file mode 100644
index 0000000..6555efe1
--- /dev/null
+++ b/packages/SettingsLib/res/values-kk-rKZ/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Қосылуда..."</item>
+    <item msgid="515055375277271756">"Растауда…"</item>
+    <item msgid="1943354004029184381">"IP мекенжайына қол жеткізуде…"</item>
+    <item msgid="4221763391123233270">"Қосылған"</item>
+    <item msgid="624838831631122137">"Уақытша тоқтатылды"</item>
+    <item msgid="7979680559596111948">"Ажыратуда…"</item>
+    <item msgid="1634960474403853625">"Ажыратылған"</item>
+    <item msgid="746097431216080650">"Сәтсіз"</item>
+    <item msgid="6367044185730295334">"Бөгелген"</item>
+    <item msgid="503942654197908005">"Нашар байланысты уақытша қолданбау"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"IP мекенжайын <xliff:g id="NETWORK_NAME">%1$s</xliff:g> арқылы алуда…"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> жалғанған"</item>
+    <item msgid="1330262655415760617">"Уақытша тоқтатылды"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> байланысынан ажыратылуда…"</item>
+    <item msgid="197508606402264311">"Ажыратылған"</item>
+    <item msgid="8578370891960825148">"Сәтсіз"</item>
+    <item msgid="5660739516542454527">"Бөгелген"</item>
+    <item msgid="1805837518286731242">"Нашар байланысты уақытша қолданбау"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
new file mode 100644
index 0000000..7d89c80
--- /dev/null
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Желілерді шолу мүмкін емес"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Аумақта жоқ"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке қатынас анықталмады, автоматты түрде қайта қосылу орындалмайды."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> сақтаған"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi көмекшісі арқылы қосылу орындалды"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s арқылы қосылған"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s арқылы қолжетімді"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Қосылған, интернет жоқ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ажыратылған"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ажыратылуда…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Жалғауда..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Жалғанған"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Жұптауда..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Жалғанған (телефон жоқ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Жалғанған (медиа жоқ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Жалғанған (хабарлар қол жетімсіз)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Жалғанған (телефон және медиа жоқ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Meдиа аудиосы"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Телефон аудиосы"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл жіберу"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Кіріс құрылғысы"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернетке қосылу"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Контактіні бөлісу"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Контактіні бөлісу үшін пайдалану"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Интернет байланысын ортақ қолдану"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Хабарға кіру"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картасына кіру"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиосына жалғанған"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Телефон аудиосына қосылған"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл жіберу серверіне жалғанған"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Картаға жалғанған"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP жүйесіне қосылған"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл жіберу серверіне жалғанбаған"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Кіріс құрылғысына косылған"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Құрылғыға интернетке кіру үшін жалғанған"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Жергілікті интернет байланысын құрылғымен ортақ пайдалану"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернетке кіру үшін қолдану"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Карта үшін қолдану"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM картасына кіру үшін пайдалану"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудиосы үшін қолдану"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосы үшін қолдану"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файлды жіберу үшін қолдану"</string>
+    <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_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 немесе кілтсөз дұрыс емес."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысымен қатынаса алмайды"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысы жұпталудан бас тартты."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi өшірулі."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi ажыратылған."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi сигналы — бір жолақ."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi сигналы — екі жолақ."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi сигналы — үш жолақ."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi сигналы толық."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android операциялық жүйесі"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Алынған қолданбалар"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Алынған қолданбалар және пайдаланушылар"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB модем режимі"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Алынбалы хот-спот"</string>
+    <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="8101244883654409696">"Жұмыс профилі"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Қонақ"</string>
+    <string name="unknown" msgid="1592123443519355854">"Белгісіз"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Пайдаланушы: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/arrays.xml b/packages/SettingsLib/res/values-km-rKH/arrays.xml
new file mode 100644
index 0000000..3c65bf3
--- /dev/null
+++ b/packages/SettingsLib/res/values-km-rKH/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"កំពុង​ត​ភ្ជាប់​…"</item>
+    <item msgid="515055375277271756">"កំពុង​ផ្ទៀងផ្ទាត់..."</item>
+    <item msgid="1943354004029184381">"កំពុង​ទទួល​អាសយដ្ឋាន IP…"</item>
+    <item msgid="4221763391123233270">"បាន​តភ្ជាប់"</item>
+    <item msgid="624838831631122137">"បាន​ពន្យារ​ពេល"</item>
+    <item msgid="7979680559596111948">"កំពុង​ផ្ដាច់…"</item>
+    <item msgid="1634960474403853625">"បាន​ផ្ដាច់"</item>
+    <item msgid="746097431216080650">"មិន​ជោគជ័យ"</item>
+    <item msgid="6367044185730295334">"បាន​ទប់​ស្កាត់"</item>
+    <item msgid="503942654197908005">"ជៀសវាង​ការ​តភ្ជាប់​ដែល​ខ្សោយ​ជា​បណ្ដោះ​អាសន្ន"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"កំពុង​យក​អាសយដ្ឋាន IP ពី <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"បាន​តភ្ជាប់​ទៅ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"បាន​ផ្អាក"</item>
+    <item msgid="7698638434317271902">"កំពុង​ផ្ដាច់​ពីរ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"បាន​ផ្ដាច់"</item>
+    <item msgid="8578370891960825148">"មិន​ជោគជ័យ"</item>
+    <item msgid="5660739516542454527">"បាន​ទប់ស្កាត់"</item>
+    <item msgid="1805837518286731242">"ជៀសវាង​ការ​តភ្ជាប់​​ខ្សោយ​ជា​បណ្ដោះអាសន្ន"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
new file mode 100644
index 0000000..59f18db
--- /dev/null
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"មិន​អាច​វិភាគ​រក​បណ្ដាញ"</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_network_failure" msgid="2364951338436007124">"ការ​កំណត់​រចនាសម្ព័ន្ធ IP បរាជ័យ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"ការ​ភ្ជាប់​ WiFi បរាជ័យ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"បញ្ហា​ក្នុង​ការ​ផ្ទៀងផ្ទាត់"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"នៅ​ក្រៅ​តំបន់"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"រក​មិន​ឃើញ​ការ​ចូល​ដំណើរការ​អ៊ីនធឺណិត, នឹង​មិន​ភ្ជាប់​ឡើង​វិញ​ដោយ​ស្វ័យ​ប្រវត្តិ​ទេ។"</string>
+    <string name="saved_network" msgid="4352716707126620811">"បានរក្សាទុកដោយ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"បានភ្ជាប់តាមរយៈជំនួយការ Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"បានភ្ជាប់តាមរយៈ %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"មានតាមរយៈ %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"បានភ្ជាប់ ប៉ុន្តែគ្មានអ៊ីនធឺណិតទេ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"បាន​ផ្ដាច់"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"កំពុង​ផ្ដាច់…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"កំពុង​ត​ភ្ជាប់​…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"បាន​តភ្ជាប់"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"កំពុង​ផ្គូផ្គង..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"បាន​តភ្ជាប់ (គ្មាន​ទូរស័ព្ទ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"បាន​តភ្ជាប់ (គ្មាន​មេឌៀ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"បាន​ភ្ជាប់ (គ្មាន​ការ​ចូល​ដំណើរការ​សារ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"បាន​តភ្ជាប់ (គ្មាន​ទូរស័ព្ទ ឬ​មេឌៀ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"សំឡេង​មេឌៀ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"សំឡេង​ទូរស័ព្ទ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ផ្ទេរ​ឯកសារ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ឧបករណ៍​បញ្ចូល"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ចូល​អ៊ីនធឺណិត"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"ការ​ចែករំលែក​​ទំនាក់ទំនង"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"ប្រើ​សម្រាប់​ការ​ចែករំលែក​ទំនាក់ទំនង"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ចែករំលែក​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"​​ចូល​ដំណើរការ​សារ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ការចូលដំណើរការស៊ីម"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"បា​ន​ភ្ជាប់​ទៅ​អូឌីយ៉ូ​មេឌៀ"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"តភ្ជាប់​ទៅ​អូឌីយ៉ូ​ទូរស័ព្ទ"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"បាន​តភ្ជាប់​ទៅ​ម៉ាស៊ីន​មេ​ផ្ទេរ​ឯកសារ"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"បាន​ភ្ជាប់​ទៅ​​​ផែនទី"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"បានភ្ជាប់ទៅ SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"មិន​បាន​តភ្ជាប់​ទៅ​ម៉ាស៊ីន​មេ​ផ្ទេរ​ឯកសារ"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"បាន​តភ្ជាប់​ទៅ​ឧបករណ៍​បញ្ចូល"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"បាន​តភ្ជាប់​​ឧបករណ៍​សម្រាប់​ចូល​អ៊ីនធឺណិត"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ចែករំលែក​ការ​តភ្ជាប់​អ៊ីនធឺណិត​មូលដ្ឋាន​ជា​មួយ​ឧបករណ៍"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ប្រើ​សម្រាប់​ចូល​អ៊ីនធឺណិត"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ប្រើ​សម្រាប់​ផែនទី"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ប្រើសម្រាប់ចូលដំណើរការស៊ីម"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ប្រើ​សម្រាប់​សំឡេង​មេឌៀ"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ប្រើ​សម្រាប់​​អូឌីយ៉ូ​ទូរស័ព្ទ"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ប្រើ​សម្រាប់​ផ្ទេរ​ឯកសារ"</string>
+    <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_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 ឬ​លេខ​កូដ​មិន​ត្រឹមត្រូវ។"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"មិន​អាច​ទាក់ទង​ជា​មួយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ។"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ការ​ផ្គូផ្គង​បាន​បដិសេធ​ដោយ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ។"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"បានបិទ Wifi"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"បានផ្តាច់ Wifi"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi មួយកាំ"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi ពីរកាំ"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi បីកាំ"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"សេវា Wifi ពេញ"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"ប្រព័ន្ធ​ប្រតិបត្តិការ Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"កម្មវិធី​ដែល​បាន​លុប"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"បាន​លុប​កម្មវិធី និង​អ្នកប្រើ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"ការ​ភ្ជាប់​យូអេសប៊ី"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ហតស្ពត​ចល័ត"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ការ​ភ្ជាប់ប៊្លូធូស"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ការ​ភ្ជាប់"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"ការ​ភ្ជាប់ &amp; ហតស្ពត​ចល័ត"</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">"អ្នកប្រើ៖ <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/arrays.xml b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
new file mode 100644
index 0000000..7e42fb4
--- /dev/null
+++ b/packages/SettingsLib/res/values-kn-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"ಸಂಪರ್ಕಪಡಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="515055375277271756">"ಪ್ರಮಾಣೀಕರಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="1943354004029184381">"IP ವಿಳಾಸವನ್ನು ಪಡೆಯಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="4221763391123233270">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</item>
+    <item msgid="624838831631122137">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</item>
+    <item msgid="7979680559596111948">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</item>
+    <item msgid="1634960474403853625">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</item>
+    <item msgid="746097431216080650">"ಯಶಸ್ವಿಯಾಗಲಿಲ್ಲ"</item>
+    <item msgid="6367044185730295334">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</item>
+    <item msgid="503942654197908005">"ಕಳಪೆ ಸಂಪರ್ಕವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ತಡೆಗಟ್ಟಲಾಗುತ್ತಿದೆ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ"</item>
+    <item msgid="1330262655415760617">"ತಡೆಹಿಡಿಯಲಾಗಿದೆ"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ನಿಂದ ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ…"</item>
+    <item msgid="197508606402264311">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</item>
+    <item msgid="8578370891960825148">"ಯಶಸ್ವಿಯಾಗಲಿಲ್ಲ"</item>
+    <item msgid="5660739516542454527">"ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</item>
+    <item msgid="1805837518286731242">"ಕಳಪೆ ಸಂಪರ್ಕವನ್ನು ತಾತ್ಕಾಲಿಕವಾಗಿ ತಡೆಗಟ್ಟಲಾಗುತ್ತಿದೆ"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
new file mode 100644
index 0000000..ef05366
--- /dev/null
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ನೆಟ್‌ವರ್ಕ್‌ಗಳಿಗಾಗಿ ಸ್ಕ್ಯಾನ್‌ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</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_network_failure" msgid="2364951338436007124">"IP ಕಾನ್ಫಿಗರೇಶನ್ ವಿಫಲತೆ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ಸಂಪರ್ಕ ವಿಫಲತೆ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ಪ್ರಮಾಣೀಕರಣ ಸಮಸ್ಯೆ"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"ವ್ಯಾಪ್ತಿಯಲ್ಲಿಲ್ಲ"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ಯಾವುದೇ ಇಂಟರ್ನೆಟ್‌ ಪ್ರವೇಶ ಪತ್ತೆಯಾಗಿಲ್ಲ, ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಮರುಸಂಪರ್ಕಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ರಿಂದ ಉಳಿಸಲಾಗಿದೆ"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ಸಹಾಯಕದ ಮೂಲಕ ಸಂಪರ್ಕಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ಮೂಲಕ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"ಸಂಪರ್ಕಗೊಳಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"ಜೋಡಿಸಲಾಗುತ್ತಿದೆ..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"ಸಂಪರ್ಕಗೊಂಡಿದೆ (ಫೋನ್ ಇಲ್ಲ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ಸಂಪರ್ಕಗೊಂಡಿದೆ (ಮಾಧ್ಯಮವಿಲ್ಲ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ (ಯಾವುದೇ ಸಂದೇಶ ಪ್ರವೇಶವಿಲ್ಲ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ಸಂಪರ್ಕಗೊಂಡಿದೆ (ಫೋನ್ ಅಥವಾ ಮಾಧ್ಯಮವಿಲ್ಲ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ಮಾಧ್ಯಮ ಆಡಿಯೋ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ಫೋನ್ ಆಡಿಯೋ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ಫೈಲ್ ವರ್ಗಾವಣೆ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ಇನ್‌ಪುಟ್‌ ಸಾಧನ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"ಸಂಪರ್ಕ ಹಂಚಿಕೆ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"ಸಂಪರ್ಕ ಹಂಚಿಕೆಗಾಗಿ ಬಳಸಿ"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕ ಹಂಚಿಕೊಳ್ಳುವಿಕೆ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"ಸಂದೇಶ ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ಸಿಮ್ ಪ್ರವೇಶ"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ಮಾಧ್ಯಮ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ಫೋನ್ ಆಡಿಯೋಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ಫೈಲ್ ವರ್ಗಾವಣೆ ಸರ್ವರ್‌ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ನಕ್ಷೆಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP ಗೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ಫೈಲ್ ವರ್ಗಾವಣೆ ಸರ್ವರ್‌ಗೆ ಸಂಪರ್ಕಗೊಳ್ಳಲಿಲ್ಲ"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ಇನ್‌ಪುಟ್‌ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಸಾಧನಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ಸಾಧನದ ಜೊತೆಗೆ ಸ್ಥಳೀಯ ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವನ್ನು ಹಂಚಿಕೊಳ್ಳಲಾಗುತ್ತಿದೆ"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ಇಂಟರ್ನೆಟ್ ಪ್ರವೇಶಕ್ಕಾಗಿ ಬಳಸಿ"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ನಕ್ಷೆಗಾಗಿ ಬಳಸಿ"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ಸಿಮ್ ಪ್ರವೇಶಕ್ಕೆ ಬಳಸಿ"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ಮಾಧ್ಯಮ ಆಡಿಯೋ ಬಳಸು"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ಫೋನ್‌ ಆಡಿಯೋಗಾಗಿ ಬಳಕೆ"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ಫೈಲ್‌ ವರ್ಗಾವಣೆಗಾಗಿ ಬಳಸು"</string>
+    <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_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> ಜೊತೆಗೆ ಜೋಡಿಸಲು ಸಾಧ್ಯವಾಗಲಿಲ್ಲ."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಜೊತೆಗೆ ಸಂವಹನ ನಡೆಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ಜೋಡಿಸುವಿಕೆಯನ್ನು <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ತಿರಸ್ಕರಿಸಿದೆ"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"ವೈಫೈ ಆಫ್."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"ವೈಫೈ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ವೈಫೈ ಒಂದು ಪಟ್ಟಿ."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ವೈಫೈ ಎರಡು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"ವೈಫೈ ಮೂರು ಪಟ್ಟಿಗಳು."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"ವೈಫೈ ಸಿಗ್ನಲ್‌‌ ಪೂರ್ತಿ ಇದೆ."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ತೆಗೆದುಹಾಕಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ಟೆಥರಿಂಗ್"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ಬ್ಲೂಟೂತ್‌‌ ಟೆಥರಿಂಗ್‌"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"ಟೆಥರಿಂಗ್‌"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"ಟೆಥರಿಂಗ್ &amp; ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</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">"ಬಳಕೆದಾರ: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ko/arrays.xml b/packages/SettingsLib/res/values-ko/arrays.xml
new file mode 100644
index 0000000..0fcb70d
--- /dev/null
+++ b/packages/SettingsLib/res/values-ko/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"연결 중…"</item>
+    <item msgid="515055375277271756">"인증하는 중..."</item>
+    <item msgid="1943354004029184381">"IP 주소를 가져오는 중..."</item>
+    <item msgid="4221763391123233270">"연결됨"</item>
+    <item msgid="624838831631122137">"일시 정지됨"</item>
+    <item msgid="7979680559596111948">"연결을 끊는 중…"</item>
+    <item msgid="1634960474403853625">"연결 끊김"</item>
+    <item msgid="746097431216080650">"실패"</item>
+    <item msgid="6367044185730295334">"차단됨"</item>
+    <item msgid="503942654197908005">"연결 불량 일시적으로 방지"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>에 연결됨"</item>
+    <item msgid="1330262655415760617">"일시 정지됨"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>에서 연결을 끊는 중..."</item>
+    <item msgid="197508606402264311">"연결 끊김"</item>
+    <item msgid="8578370891960825148">"실패"</item>
+    <item msgid="5660739516542454527">"차단됨"</item>
+    <item msgid="1805837518286731242">"연결 상태 불량 일시적으로 방지"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
new file mode 100644
index 0000000..75396cb
--- /dev/null
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"네트워크를 검색할 수 없습니다."</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"범위 내에 없음"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"감지된 인터넷 액세스가 없으며 자동으로 다시 연결되지 않습니다."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g>(으)로 저장됨"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi 도우미를 통해 연결됨"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s을(를) 통해 연결됨"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s을(를) 통해 사용 가능"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"인터넷을 사용하지 않고 연결됨"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"연결 끊김"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"연결을 끊는 중…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"연결 중…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"연결됨"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"페어링 중..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"연결됨(전화 없음)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"연결됨(미디어 없음)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"연결됨(메시지 액세스 없음)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"연결됨(전화 또는 미디어 없음)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"미디어 오디오"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"휴대폰 오디오"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"파일 전송"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"입력 장치"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"인터넷 액세스"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"연락처 공유"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"연락처 공유용"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"인터넷 연결 공유"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"메시지 액세스"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 액세스"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"미디어 오디오에 연결됨"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"휴대전화 오디오에 연결됨"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"파일 전송 서버에 연결됨"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"지도에 연결됨"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP에 연결됨"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"파일 전송 서버에 연결되지 않았습니다."</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"입력 장치에 연결됨"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"인터넷 액세스를 위해 기기에 연결됨"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"로컬 인터넷 연결을 기기와 공유 중"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"인터넷 액세스에 사용"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"지도에 사용"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM 액세스에 사용"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"미디어 오디오에 사용"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"휴대전화 오디오에 사용"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"파일 전송에 사용"</string>
+    <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_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">"PIN 또는 패스키가 잘못되어 <xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 페어링하지 못했습니다."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>와(과) 통신할 수 없습니다."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>에서 페어링을 거부했습니다."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi가 꺼져 있습니다."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi 연결이 끊어졌습니다."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi 신호 막대가 한 개입니다."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi 신호 막대가 두 개입니다."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi 신호 막대가 세 개입니다."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi 신호가 강합니다."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"삭제된 앱"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"삭제된 앱 및 사용자"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 테더링"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"휴대용 핫스팟"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"블루투스 테더링"</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="8101244883654409696">"직장 프로필"</string>
+    <string name="user_guest" msgid="8475274842845401871">"손님"</string>
+    <string name="unknown" msgid="1592123443519355854">"알 수 없음"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"사용자: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/arrays.xml b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
new file mode 100644
index 0000000..207dea1
--- /dev/null
+++ b/packages/SettingsLib/res/values-ky-rKG/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Туташууда…"</item>
+    <item msgid="515055375277271756">"Аныктыгы текшерилүүдө…"</item>
+    <item msgid="1943354004029184381">"IP дареги алынууда…"</item>
+    <item msgid="4221763391123233270">"Туташып турат"</item>
+    <item msgid="624838831631122137">"Убактылуу токтотулду"</item>
+    <item msgid="7979680559596111948">"Ажыратылууда…"</item>
+    <item msgid="1634960474403853625">"Ажыратылды"</item>
+    <item msgid="746097431216080650">"Ийгиликсиз"</item>
+    <item msgid="6367044185730295334">"Бөгөттөлгөн"</item>
+    <item msgid="503942654197908005">"Начар байланыштан убактылуу баш тартууда"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагына туташты"</item>
+    <item msgid="1330262655415760617">"Убактылуу токтотулду"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> тармагынан ажыратылууда…"</item>
+    <item msgid="197508606402264311">"Ажыратылды"</item>
+    <item msgid="8578370891960825148">"Ийгиликсиз"</item>
+    <item msgid="5660739516542454527">"Бөгөттөлгөн"</item>
+    <item msgid="1805837518286731242">"Начар байланыштан убактылуу баш тартууда"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
new file mode 100644
index 0000000..258b8eb
--- /dev/null
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Түйүндөрдү издөө мүмкүн эмес"</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_network_failure" msgid="2364951338436007124">"IP конфигурациясы бузулду"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi туташуусу бузулду"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Аутентификация маселеси бар"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Тейлөө аймагында эмес"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернетке кирүү мүмкүнчүлүгү табылган жок, андыктан автоматтык түрдө кайра туташпайт."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi жардамчысы аркылуу туташып турат"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s аркылуу жеткиликтүү"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Туташып турат, Интернет жок"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ажыратылды"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Ажыратылууда…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Туташууда…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Туташып турат"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Жупташтырылууда…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Туташып турат (телефониясыз)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Туташып турат (медиасыз)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Байланышта (билдирүү алмашуу жок)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Туташып турат (телефониясыз же медиасыз)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аудио"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Телефон"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл алмашуу"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Киргизүү түзмөгү"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернетке мүмкүнчүлүк алуу"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Байланышты бөлүшүү"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Байланышты бөлүшүү үчүн колдонуу"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Интернет байланышын бөлүшүү"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Билдирүү алмашуу"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM картаны пайдалануу мүмкүнчүлүгү"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиого туташты"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Телефон аудиосуна туташты"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл өткөрүү серверине туташты"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"MAP\'ка байланышты"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP\'ка туташып турат"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл өткөрүү серверине туташкан жок"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Киргизүү түзмөгүнө туташты"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Интернетке мүмкүнчүлүк алуу үчүн түзмөккө туташты"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Жергиликтүү Интернет туташуусу түзмөк менен бөлүшүлүүдө"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернетке мүмкүнчүлүк алуу үчүн колдонулсун"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"MAP үчүн колдонуу"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM картаны пайдалануу үчүн колдонуу"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудио үчүн колдонуу"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Телефон аудиосу үчүн колдонулсун"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файл өткөрүү үчүн колдонулсун"</string>
+    <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_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">"PIN же код туура эмес болгондуктан <xliff:g id="DEVICE_NAME">%1$s</xliff:g> туташуу мүмкүн эмес."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> менен байланышуу мүмкүн эмес."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Жупташтырууну <xliff:g id="DEVICE_NAME">%1$s</xliff:g> четке какты."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi өчүк."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi туташуусу жок."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi: бир таякча."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi: эки таякча."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi: үч таякча."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi: күчтүү сигнал."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Алынып салынган колдонмолор"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Өчүрүлгөн колдонмолор жана колдонуучулар"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB жалгаштыруу"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ташыма кошулуу чекити"</string>
+    <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="8101244883654409696">"Жумуш профили"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Конок"</string>
+    <string name="unknown" msgid="1592123443519355854">"Белгисиз"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Колдонуучу: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/arrays.xml b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
new file mode 100644
index 0000000..799a6ec
--- /dev/null
+++ b/packages/SettingsLib/res/values-lo-rLA/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"ກຳລັງເຊື່ອມຕໍ່..."</item>
+    <item msgid="515055375277271756">"ກຳລັງພິສູດຢືນຢັນ..."</item>
+    <item msgid="1943354004029184381">"ກຳລັງຂໍທີ່ຢູ່ IP..."</item>
+    <item msgid="4221763391123233270">"ເຊື່ອມຕໍ່ແລ້ວ"</item>
+    <item msgid="624838831631122137">"ຖືກລະງັບໄວ້"</item>
+    <item msgid="7979680559596111948">"ກຳລັງຕັດການເຊື່ອມຕໍ່..."</item>
+    <item msgid="1634960474403853625">"ບໍ່ໄດ້ເຊື່ອມຕໍ່"</item>
+    <item msgid="746097431216080650">"ບໍ່ສຳເລັດ"</item>
+    <item msgid="6367044185730295334">"ບລັອກແລ້ວ"</item>
+    <item msgid="503942654197908005">"ຫຼີກເວັ້ນການເຊື່ອມຕໍ່ຊົ່ວຄາວຫາກສັນຍານບໍ່ແຮງພໍ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"ກຳລັງຂໍທີ່ຢູ່ IP ຈາກ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"ເຊື່ອມ​ຕໍ່​ກັບ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> ແລ້ວ"</item>
+    <item msgid="1330262655415760617">"ຖືກລະງັບແລ້ວ"</item>
+    <item msgid="7698638434317271902">"ກຳລັງຕັດການເຊື່ອມຕໍ່ຈາກ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"ປິດການເຊື່ອມຕໍ່ແລ້ວ"</item>
+    <item msgid="8578370891960825148">"ບໍ່ສຳເລັດ"</item>
+    <item msgid="5660739516542454527">"ປິດກັ້ນແລ້ວ"</item>
+    <item msgid="1805837518286731242">"ຫຼີກເວັ້ນການເຊື່ອມຕໍ່ເຄືອຂ່າຍສັນຍານອ່ອນຊົ່ວຄາວ"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
new file mode 100644
index 0000000..ba29eab
--- /dev/null
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ບໍ່ສາມາດກວດຫາເຄືອຂ່າຍໄດ້"</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_network_failure" msgid="2364951338436007124">"ການ​ຕັ້ງ​ຄ່າ IP ລົ້ມ​ເຫຼວ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"​ການ​ເຊື່ອມ​ຕໍ່ WiFi ລົ້ມ​ເຫຼວ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ບັນຫາການພິສູດຢືນຢັນ"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"ບໍ່ຢູ່ໃນໄລຍະທີ່ເຊື່ອມຕໍ່ໄດ້"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"​ບໍ່​ພົບ​ການ​ເຊື່ອມ​ຕໍ່​ອິນ​ເຕີ​ເນັດ​, ຈະ​ບໍ່​ຖືກ​ເຊື່ອມ​ຕໍ່​ໃໝ່​ໂດຍ​ອັດ​ຕະ​ໂນ​ມັດ."</string>
+    <string name="saved_network" msgid="4352716707126620811">"ບັນທຶກ​​​ໂດຍ <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"ເຊື່ອມ​ຕໍ່​ຜ່ານ Wi‑Fi ຕົວ​ຊ່ວຍ​ແລ້ວ"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"​ເຊື່ອມຕໍ່​ຜ່ານ %1$s ​ແລ້ວ"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"ມີ​ໃຫ້​ຜ່ານ %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"​ເຊື່ອມ​ຕໍ່​ແລ້ວ,​ ບໍ່​ມີ​ອິນ​ເຕີ​ເນັດ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ກຳລັງຢຸດການເຊື່ອມຕໍ່..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"ກຳລັງເຊື່ອມຕໍ່..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"ເຊື່ອມ​ຕໍ່ແລ້ວ"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"ກຳລັງຈັບຄູ່..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"ເຊື່ອມຕໍ່ແລ້ວ (ບໍ່ມີໂທລະສັບ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ເຊື່ອມຕໍ່ແລ້ວ (ບໍ່ມີສື່)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ເຊື່ອມຕໍ່ (ບໍ່ມີການເຂົ້າເຖິງຂໍ້ຄວາມ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ເຊື່ອມຕໍ່ແລ້ວ (ບໍ່ມີໂທລະສັບ ຫຼືສື່)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ສຽງ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ສຽງໂທລະສັບ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ການໂອນຍ້າຍໄຟລ໌"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ອຸປະກອນປ້ອນຂໍ້ມູນ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ການເຂົ້າເຖິງອິນເຕີເນັດ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"ການ​ແບ່ງ​ປັນ​ລາຍ​ຊື່​ຜູ່​ຕິດ​ຕໍ່"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"​ໃຊ້​ສຳ​ລັບການ​ແບ່ງ​ປັນ​ລາຍ​ຊື່​ຜູ່​ຕິດ​ຕໍ່"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ການແບ່ງປັນການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"ການ​ເຂົ້າ​ເຖິງ​ຂໍ້​ຄວາມ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"ການ​ເຂົ້າ​ເຖິງ SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ເຊື່ອມຕໍ່ກັບສື່ດ້ານສຽງແລ້ວ"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ເຊື່ອມຕໍ່ກັບສຽງໂທລະສັບແລ້ວ"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ເຊື່ອມຕໍ່ກັບເຊີບເວີໂອນຍ້າຍໄຟລ໌ແລ້ວ"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ເຊື່ອມ​ຕໍ່​ກັບ​ແຜນ​ທີ່ແລ້ວ"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"ເຊື່ອມ​ຕໍ່​ກັບ SAP ​ແລ້ວ"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ບໍ່ໄດ້ເຊື່ອມຕໍ່ຫາເຊີບເວີໂອນຍ້າຍໄຟລ໌"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ເຊື່ອມຕໍ່ກັບອຸປະກອນປ້ອນຂໍ້ມູນແລ້ວ"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ເຊື່ອມຕໍ່ກັບອຸປະກອນເພື່ອເຂົ້າເຖິງອິນເຕີເນັດແລ້ວ"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ກຳລັງແບ່ງປັນການເຊື່ອມຕໍ່ອິນເຕີເນັດກັບອຸປະກອນ"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ໃຊ້ເພື່ອເຂົ້າອິນເຕີເນັດ"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ໃຊ້ສຳລັບແຜນທີ່"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ການ​ໃຊ້​ສໍາ​ລັບ​ການ​ເຂົ້າ​ເຖິງ SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ໃຊ້ສຳລັບສື່ດ້ານສຽງ"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ໃຊ້ສຳລັບລະບົບສຽງຂອງໂທລະສັບ"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ໃຊ້ເພື່ອໂອນຍ້າຍໄຟລ໌"</string>
+    <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_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 ຫຼື passkey ບໍ່ຖືກຕ້ອງ."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ບໍ່ສາມາດຕິດຕໍ່ສື່ສານກັບ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ໄດ້."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ການຈັບຄູ່ຖືກປະຕິເສດໂດຍ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"WiFi ປິດຢູ່."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"ຕັດການເຊື່ອມຕໍ່ Wi-Fi ແລ້ວ."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ສັນຍານ Wi-Fi ນຶ່ງຂີດ."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ສັນຍານ Wi-Fi ສອງຂີດ."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi ສາມຂີດ."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"ສັນຍານ Wi-Fi ເຕັມ"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ແອັບຯທີ່ຖືກລຶບອອກແລ້ວ"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ລຶບແອັບຯ ແລະຜູ່ໃຊ້ແລ້ວ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"ການປ່ອຍສັນຍານຜ່ານ USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ຮັອດສະປອດເຄື່ອນທີ່"</string>
+    <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">"ການປ່ອຍສັນຍານ &amp; ຮັອດສະປອດເຄື່ອນທີ່"</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">"ຜູ່ໃຊ້: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-lt/arrays.xml b/packages/SettingsLib/res/values-lt/arrays.xml
new file mode 100644
index 0000000..8b16385
--- /dev/null
+++ b/packages/SettingsLib/res/values-lt/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Nuskaitoma..."</item>
+    <item msgid="8513729475867537913">"Prisijungiama..."</item>
+    <item msgid="515055375277271756">"Nustatoma tapatybė..."</item>
+    <item msgid="1943354004029184381">"Gaunamas IP adresas..."</item>
+    <item msgid="4221763391123233270">"Prisijungta"</item>
+    <item msgid="624838831631122137">"Pristabdyta"</item>
+    <item msgid="7979680559596111948">"Atjungiama..."</item>
+    <item msgid="1634960474403853625">"Atsijungęs (-usi)"</item>
+    <item msgid="746097431216080650">"Nesėkminga"</item>
+    <item msgid="6367044185730295334">"Užblokuota"</item>
+    <item msgid="503942654197908005">"Laikinai vengiama prasto ryšio"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Nuskaitoma..."</item>
+    <item msgid="355508996603873860">"Prijungiama prie <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Nustatoma tapatybė su <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Gaunamas IP adresas iš <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Prijungta prie <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Pristabdyta"</item>
+    <item msgid="7698638434317271902">"Atjungiama nuo <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Atsijungęs (-usi)"</item>
+    <item msgid="8578370891960825148">"Nesėkminga"</item>
+    <item msgid="5660739516542454527">"Užblokuota"</item>
+    <item msgid="1805837518286731242">"Laikinai vengiama prasto ryšio"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
new file mode 100644
index 0000000..c1758b0
--- /dev/null
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nepavyksta nuskaityti tinklų"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nėra"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Išsaugotas"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Neleidžiama"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfigūracijos triktis"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"„Wi-Fi“ ryšio triktis"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentifikavimo problema"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ne diapazone"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Neaptikta jokia prieiga prie interneto, nebus automatiškai iš naujo prisijungta."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Išsaugojo <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Prisijungta naudojant „Wi‑Fi“ pagelbiklį"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Prisijungta naudojant „%1$s“"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Pasiekiama naudojant „%1$s“"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Prisijungta, nėra interneto"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Atsijungęs (-usi)"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Atjungiama..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Prisijungiama..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Prisijungta"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Susiejama..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Prijungta (be telefono)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Prijungta (be laikmenos)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Prisijungta (be prieigos prie pranešimų)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Prijungta (be telefono ar laikmenos)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Laikmenos garsas"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefono garsas"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failo perkėlimas"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Įvesties įrenginys"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Prieiga prie interneto"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktų bendrinimas"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Naudoti kontaktams bendrinti"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Interneto ryšio bendrinimas"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Prieiga prie pranešimų"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM prieiga"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Prijungta prie medijos garso įrašo"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Prijungta prie telefono garso"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Prijungta prie failų perkėlimo serverio"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Prisijungta prie žemėlapio"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Prisijungta prie SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Neprijungta prie failų perkėlimo serverio"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Prisijungta prie įvesties įrenginio."</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pr. prie įr., kad gaut. pr. prie int."</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Bendr. vt. int. ryš. su įr."</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Naudoti interneto prieigai"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Naudoti žemėlapyje"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Naudoti SIM prieigai"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Naudoti medijos garsui"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Naudoti telefono garso įrašui"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Naudoti failų perkėlimui"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Naudoti įvedant"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Susieti"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SUSIETI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Atšaukti"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Susiejus suteikiama prieiga prie kontaktų ir skambučių istorijos, esant prisijungus."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nepavyko susieti su „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nepavyko susieti su „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ dėl netinkamo PIN kodo ar prieigos rakto."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nepavyksta užmegzti ryšio su „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Susiejimą atmetė <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"„Wi-Fi“ išjungtas."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"„Wi-Fi“ atjungtas."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Viena „Wi-Fi“ signalo juosta."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dvi „Wi-Fi“ signalo juostos."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Trys „Wi-Fi“ signalo juostos."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Stiprus „Wi-Fi“ signalas."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"„Android“ OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Pašalintos programos"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Pašalintos programos ir naudotojai"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB susiejimas"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Perkeliama aktyvioji sritis"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"„Bluetooth“ susiejimas"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Susiejimas"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Susiej. ir perk. vieš. int. pr. tašk."</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Darbo profilis"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Svečias"</string>
+    <string name="unknown" msgid="1592123443519355854">"Nežinomas"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Naudotojas: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Nustatyti kai kurie numatytieji nustatymai"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nenustatyta jokių numatytųjų nustatymų"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-lv/arrays.xml b/packages/SettingsLib/res/values-lv/arrays.xml
new file mode 100644
index 0000000..40ba222
--- /dev/null
+++ b/packages/SettingsLib/res/values-lv/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Notiek skenēšana..."</item>
+    <item msgid="8513729475867537913">"Notiek savienojuma izveide…"</item>
+    <item msgid="515055375277271756">"Notiek autentificēšana..."</item>
+    <item msgid="1943354004029184381">"Notiek IP adreses iegūšana…"</item>
+    <item msgid="4221763391123233270">"Izveidots savienojums"</item>
+    <item msgid="624838831631122137">"Atlikts"</item>
+    <item msgid="7979680559596111948">"Notiek atvienošana..."</item>
+    <item msgid="1634960474403853625">"Atvienots"</item>
+    <item msgid="746097431216080650">"Neizdevās"</item>
+    <item msgid="6367044185730295334">"Bloķēts"</item>
+    <item msgid="503942654197908005">"Pagaidām netiek izmantots vājš savienojums."</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Notiek skenēšana..."</item>
+    <item msgid="355508996603873860">"Notiek savienojuma izveide ar <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Notiek autentificēšana ar <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Notiek IP adreses iegūšana no <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Savienots ar <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Atlikts"</item>
+    <item msgid="7698638434317271902">"Notiek atvienošana no <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Atvienots"</item>
+    <item msgid="8578370891960825148">"Neizdevās"</item>
+    <item msgid="5660739516542454527">"Bloķēts"</item>
+    <item msgid="1805837518286731242">"Pagaidām netiek izmantots vājš savienojums."</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
new file mode 100644
index 0000000..8dc762a
--- /dev/null
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nevar skenēt tīklus"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nav"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Saglabāts"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Atspējots"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP konfigurācijas kļūme"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi savienojuma kļūme"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentificēšanas problēma"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Nav diapazona ietvaros"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nevar noteikt interneta savienojumu. Savienojums netiks izveidots vēlreiz automātiski."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Saglabāja: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Izveidots savienojums ar Wi‑Fi palīgu"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Savienots, izmantojot %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Pieejams, izmantojot %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Savienots, nav piekļuves internetam"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Atvienots"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Notiek atvienošana..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Notiek savienojuma izveide…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Izveidots savienojums"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Notiek pāra izveide..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Savienojums ir izveidots (nav tālruņa)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Sav. ir izveidots (nav multivides)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Savienots (nav piekļuves ziņojumam)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Sav. ir izveidots (nav tel. vai multiv.)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Multivides audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Tālruņa audio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Failu pārsūtīšana"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Ievades ierīce"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Interneta piekļuve"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktpersonas informācijas kopīgošana"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Izmantot kontaktpersonas informācijas kopīgošanai"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Interneta savienojuma koplietošana"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Piekļuve ziņojumam"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Piekļuve SIM kartei"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Savienots ar multivides audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Savienots ar tālruņa audio"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Savienots ar failu pārsūtīšanas serveri"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Izveidots savienojums ar karti"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Savienots ar SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nav savienots ar failu pārsūtīšanas serveri"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Izveidots savienojums ar ievades ierīci"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Savien. ar ier., lai nodr. int. piekļ."</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Tiek kopliet. lok. intern. savien. ar ierīci"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Izmantot, lai piekļūtu internetam"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Lietot kartei"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Izmantot, lai piekļūtu SIM kartei"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Izmantot multivides skaņai"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Izmantot tālruņa skaņai"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Izmantot faila pārsūtīšanai"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Izmantot ievadei"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Izveidot pāri"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SAVIENOT PĀRĪ"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Atcelt"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Veicot savienošanu pārī, šī ierīce savienojuma laikā varēs piekļūt jūsu kontaktpersonām un zvanu vēsturei."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nevarēja savienot pārī ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nevarēja savienot pārī ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, jo tika ievadīts nepareizs PIN kods vai nepareiza ieejas atslēga."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nevar sazināties ar ierīci <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> noraidīja pāra izveidi."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi savienojums izslēgts"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi savienojums pārtraukts"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: viena josla"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: divas joslas"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: trīs joslas"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Pilna piekļuve Wi-Fi signālam"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Noņemtās lietotnes"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Noņemtās lietotnes un lietotāji"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB saistīšana"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Pārnēsājams tīklājs"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth saistīšana"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Saistīšana"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Piesaiste un pārn. tīklājs"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Darba profils"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Viesis"</string>
+    <string name="unknown" msgid="1592123443519355854">"Nezināms"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Lietotājs: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Iestatīti daži noklusējumi"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nav iestatīti noklusējumi"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/arrays.xml b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
new file mode 100644
index 0000000..5c51a7d
--- /dev/null
+++ b/packages/SettingsLib/res/values-mk-rMK/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Се поврзува..."</item>
+    <item msgid="515055375277271756">"Автентицирање..."</item>
+    <item msgid="1943354004029184381">"Добивање ИП адреса..."</item>
+    <item msgid="4221763391123233270">"Поврзана"</item>
+    <item msgid="624838831631122137">"Суспендирана"</item>
+    <item msgid="7979680559596111948">"Се исклучува..."</item>
+    <item msgid="1634960474403853625">"Исклучено"</item>
+    <item msgid="746097431216080650">"Неуспешна"</item>
+    <item msgid="6367044185730295334">"Блокирана"</item>
+    <item msgid="503942654197908005">"Привремено избегнува лоша врска"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>..."</item>
+    <item msgid="8937994881315223448">"Поврзано на <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Суспендирана"</item>
+    <item msgid="7698638434317271902">"Исклучување од <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Исклучено"</item>
+    <item msgid="8578370891960825148">"Неуспешна"</item>
+    <item msgid="5660739516542454527">"Блокирано"</item>
+    <item msgid="1805837518286731242">"Привремено избегнува лоша врска"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
new file mode 100644
index 0000000..384c9b7
--- /dev/null
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не може да скенира за мрежи"</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_network_failure" msgid="2364951338436007124">"Конфигурирањето ИП не успеа"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Поврзувањето преку Wi-Fi не успеа"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Проблем со автентикација"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Надвор од опсег"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Не е откриен пристап до интернет, нема автоматски повторно да се поврзете."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Зачувано од <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Поврзано преку помошник за Wi-Fismile"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Поврзано преку %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Достапно преку %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Поврзана, нема интернет"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Исклучено"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Се исклучува..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Се поврзува..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Поврзани"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Поврзување..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Поврзани (без телефон)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Поврзани (без медиуми)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Поврзано (без порака за пристап)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Поврзан (без телефон или медиуми)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Аудио на медиуми"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Аудио на телефон"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Пренос на датотека"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Влезен уред"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Пристап на интернет"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Споделување контакти"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Користи за споделување контакти"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Споделување конекција на интернет"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Порака за пристап"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Пристап до СИМ"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Поврзан со аудио на медиуми"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Поврзан со аудио на телефон"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Поврзан со сервер за пренос на датотеки"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Поврзано со карта"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Поврзано со SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Не е поврзан со сервер за пренос на датотеки"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Поврзан со влезен уред"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Поврзан со уред за пристап на интернет"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Споделување локална конекција на интернет со уред"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Користи за пристап на интернет"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Користи за карта"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Користете се пристап до СИМ"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Користи за аудио на медиуми"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Користи за аудио на телефон"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Користи за пренос на датотеки"</string>
+    <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_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> поради погрешен ПИН или лозинка."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не може да комуницира со <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Спарувањето е одбиено од <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi е исклучено."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi е исклучено."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Една црта на Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Две црти на Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Три црти на Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Полн сигнал на Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Оперативен систем Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Отстранети апликации"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Отстранети апликации и корисници"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Поврзување со УСБ"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносл. точка на пристап"</string>
+    <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="8101244883654409696">"Работен профил"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Гостин"</string>
+    <string name="unknown" msgid="1592123443519355854">"Непознато"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Корисник: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/arrays.xml b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
new file mode 100644
index 0000000..4d3261a
--- /dev/null
+++ b/packages/SettingsLib/res/values-ml-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"കണക്‌റ്റുചെയ്യുന്നു..."</item>
+    <item msgid="515055375277271756">"പ്രാമാണീകരിക്കുന്നു..."</item>
+    <item msgid="1943354004029184381">"IP വിലാസം നേടുന്നു..."</item>
+    <item msgid="4221763391123233270">"കണക്റ്റുചെയ്‌തു"</item>
+    <item msgid="624838831631122137">"താൽക്കാലികമായി നിർത്തി"</item>
+    <item msgid="7979680559596111948">"വിച്‌ഛേദിക്കുന്നു..."</item>
+    <item msgid="1634960474403853625">"വിച്ഛേദിച്ചു"</item>
+    <item msgid="746097431216080650">"പരാജയപ്പെട്ടു"</item>
+    <item msgid="6367044185730295334">"തടഞ്ഞിരിക്കുന്നു"</item>
+    <item msgid="503942654197908005">"മോശം കണക്ഷൻ താൽക്കാലികമായി ഒഴിവാക്കുന്നു"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിൽ കണക്‌റ്റുചെയ്‌തു"</item>
+    <item msgid="1330262655415760617">"താൽക്കാലികമായി നിർത്തി"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> എന്നതിൽ നിന്ന് വിച്‌ഛേദിക്കുന്നു..."</item>
+    <item msgid="197508606402264311">"വിച്ഛേദിച്ചു"</item>
+    <item msgid="8578370891960825148">"പരാജയപ്പെട്ടു"</item>
+    <item msgid="5660739516542454527">"തടഞ്ഞിരിക്കുന്നു"</item>
+    <item msgid="1805837518286731242">"മോശം കണക്ഷൻ താൽക്കാലികമായി ഒഴിവാക്കുന്നു"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
new file mode 100644
index 0000000..2977e75
--- /dev/null
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"നെ‌റ്റ്‌വർക്കുകൾക്കായി സ്കാൻ ചെയ്യാനായില്ല"</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_network_failure" msgid="2364951338436007124">"IP കോൺഫിഗറേഷൻ പരാജയം"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi കണക്ഷൻ പരാജയം"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ആധികാരികമാക്കുന്നതിലെ പ്രശ്‌നം"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"പരിധിയിലില്ല"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ഇന്റർനെറ്റ് ആക്സസ്സൊന്നും കണ്ടെത്താത്തതിനാൽ സ്വയം വീണ്ടും കണക്‌റ്റുചെയ്യില്ല."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> സംരക്ഷിച്ചത്"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"വൈഫൈ അസിസ്റ്റന്റ് മുഖേന കണക്‌റ്റുചെയ്തു"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s വഴി ബന്ധിപ്പിച്ചു"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s വഴി ലഭ്യം"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"കണക്റ്റുചെയ്തിരിക്കുന്നു, ഇന്റർനെറ്റില്ല"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"വിച്ഛേദിച്ചു"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"വിച്‌ഛേദിക്കുന്നു..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"കണക്‌റ്റുചെയ്യുന്നു..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"കണക്റ്റുചെയ്‌തു"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"ജോടിയാക്കുന്നു…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"കണ‌ക്റ്റുചെയ്‌തു (ഫോൺ ഇല്ല)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"കണക്‌റ്റുചെയ്‌തു (മീഡിയ ഇല്ല)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"കണക്റ്റുചെയ്‌തു (സന്ദേശ ആക്‌സസ്സില്ല)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"കണ‌ക്റ്റുചെ‌യ്തു (ഫോണോ മീഡിയയോ അല്ല)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"മീഡിയ ഓഡിയോ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ഫോൺ ഓഡിയോ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ഫയൽ കൈമാറൽ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ഇൻപുട്ട് ഉപകരണം"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ഇന്റർനെറ്റ് ആക്‌സസ്സ്"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"കോൺടാക്‌റ്റ് പങ്കിടൽ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"കോൺടാക്‌റ്റ് പങ്കിടലിനായി ഉപയോഗിക്കുക"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ഇന്റർനെറ്റ് കണക്ഷൻ പങ്കിടൽ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"ആക്‌സസ്സ് നിയന്ത്രിക്കുക"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ആക്സസ്"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"മീഡിയ ഓഡിയോയിലേക്ക് കണ‌ക്റ്റുചെയ്‌തു"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ഫോൺ ഓഡിയോയിൽ കണ‌ക്റ്റുചെ‌യ്‌തു"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ഫയൽ കൈമാറ്റ സെർവറിലേക്ക് കണ‌ക്റ്റുചെ‌യ്‌തു"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"മാപ്പിലേക്ക് കണക്റ്റുചെയ്‌തു"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-യിലേക്ക് ബന്ധിപ്പിച്ചു"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ഫയൽ കൈമാറ്റ സെർവറിൽ കണ‌ക്റ്റുചെയ്‌തിട്ടില്ല"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ഇൻപുട്ട് ഉപകരണത്തിൽ കണക്റ്റുചെയ്‌തു"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ഇന്റ‌ർനെറ്റ് ആക്‌‌സസ്സിനായി ഉപകരണത്തിൽ കണ‌ക്‌റ്റുചെയ്‌തു"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ഉപകരണവുമായി പ്രദേശിക ഇന്റ‌ർനെറ്റ്‌ കണക്ഷൻ പങ്കിടുന്നു"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ഇന്റ‌ർനെറ്റ് ആക്‌‌സസ്സിനായി ഉപയോഗിക്കുന്നു"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"മാപ്പിനായി ഉപയോഗിക്കുക"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ആക്സസിന് ഉപയോഗിക്കുക"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"മീഡിയ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ഫോൺ ഓഡിയോയ്ക്കായി ഉപയോഗിക്കുക"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ഫയൽ കൈമാറ്റത്തിനായി ഉപയോഗിക്കുന്നു"</string>
+    <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_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> എന്നതുമായി ജോടിയാക്കാനായില്ല."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> എന്നതുമായി ആശയവിനിമയം നടത്താനായില്ല."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>, ജോടിയാക്കൽ നിരസിച്ചു."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"വൈഫൈ ഓഫാണ്."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"വൈഫൈ വിച്ഛേദിച്ചു."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"വൈഫൈ സിഗ്നൽ ഒരു ബാർ."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"വൈഫൈ സിഗ്നൽ രണ്ട് ബാറുകൾ."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"വൈഫൈ സിഗ്നൽ മൂന്ന് ബാറുകൾ."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"വൈഫൈ മികച്ച സിഗ്‌നൽ."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"നീക്കംചെയ്‌ത അപ്ലിക്കേഷനുകൾ"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"നീക്കംചെയ്‌ത അപ്ലിക്കേഷനുകളും ഉപയോക്താക്കളും"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ടെതറിംഗ്"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"പോർട്ടബിൾ ഹോട്ട്സ്‌പോട്ട്"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ബ്ലൂടൂത്ത് ടെതറിംഗ്"</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="8101244883654409696">"ഔദ്യോഗിക പ്രൊഫൈൽ"</string>
+    <string name="user_guest" msgid="8475274842845401871">"അതിഥി"</string>
+    <string name="unknown" msgid="1592123443519355854">"അജ്ഞാതം"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"ഉപയോക്താവ്: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/arrays.xml b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
new file mode 100644
index 0000000..2849b51
--- /dev/null
+++ b/packages/SettingsLib/res/values-mn-rMN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Холбогдож байна..."</item>
+    <item msgid="515055375277271756">"Гэрчлэж байна"</item>
+    <item msgid="1943354004029184381">"IP хаягийг авч байна…"</item>
+    <item msgid="4221763391123233270">"Холбогдсон"</item>
+    <item msgid="624838831631122137">"Түр хаасан"</item>
+    <item msgid="7979680559596111948">"Салгаж байна…"</item>
+    <item msgid="1634960474403853625">"Салгагдсан"</item>
+    <item msgid="746097431216080650">"Амжилтгүй"</item>
+    <item msgid="6367044185730295334">"Хориглогдсон"</item>
+    <item msgid="503942654197908005">"Муу холболтоос түр зайлсхийж байна"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> руу холбогдсон"</item>
+    <item msgid="1330262655415760617">"Түр хаасан"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>-с салгагдаж байна…"</item>
+    <item msgid="197508606402264311">"Салгагдсан"</item>
+    <item msgid="8578370891960825148">"Амжилтгүй"</item>
+    <item msgid="5660739516542454527">"Хориглогдсон"</item>
+    <item msgid="1805837518286731242">"Муу холболтоос түр зайлсхийж байна"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
new file mode 100644
index 0000000..ed93627
--- /dev/null
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Сүлжээнүүдийг скан хийх боломжгүй"</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_network_failure" msgid="2364951338436007124">"IP тохируулга амжилтгүй"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi холболт амжилтгүй"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Гэрчлэлийн асуудал"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Хүрээнд байхгүй"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Интернэт холболт илэрсэнгүй, автоматаар дахин холболт хийгдэхгүй"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> хадгалсан"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi туслагчаар дамжуулан холбогдлоо"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s-р холбогдсон"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s-р боломжтой"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Холбогдсон, интернэт байхгүй байна"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Салгагдсан"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Салгаж байна…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Холбогдож байна..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Холбогдсон"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Хослуулж байна…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Холбогдсон (утас байхгүй)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Холбогдсон (медиа байхгүй)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Холбогдсон (зурвас хандалт байхгүй)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Холбогдсон (утас буюу медиа байхгүй)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Медиа аудио"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Утасны аудио"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Файл дамжуулалт"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Оруулах төхөөрөмж"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернэт хандалт"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Харилцагч хуваалцах"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Харилцагч хуваалцахад ашиглах"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Интернэт холболтыг хуваалцах"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Зурвас хандалт"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Хандалт"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Медиа аудиод холбогдсон"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Утасны аудид холбогдсон"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Файл дамжуулах серверт холбогдсон"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Газрын зурагтай холбогдсон"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP-д холбогдсон"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Файл дамжуулах серверт холбогдоогүй"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Оруулах төхөөрөмжтэй холбогдсон"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Интернетэд хандахын тулд төхөөрөмжтэй холбогдсон"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Төхөөрөмжтэй локал Интернет холболтыг хуваалцаж байна"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Интернет хандалтанд ашиглах"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Газрын зурагт ашиглах"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM хандалтад ашиглах"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Медиа аудиод ашиглах"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Утасны аудиод ашиглах"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Файл дамжуулахад ашиглах"</string>
+    <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_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">"Буруу PIN эсхүл дамжих түлхүүрээс шалтгаалан <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай хослуулж чадсангүй."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>-тай холбоо барих боломжгүй."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Хослуулахаас <xliff:g id="DEVICE_NAME">%1$s</xliff:g> татгалзсан."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi унтраалттай байна."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi холбогдоогүй байна."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi сүлжээний дохио нэг баганатай байна."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi сүлжээний дохио хоёр баганатай байна."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi сүлжээний дохио гурван баганатай байна."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi-н дохио дүүрэн байна."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Андройд OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Арилгасан апп-ууд"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Арилгасан апп-ууд болон хэрэглэгчид"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB модем болгох"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Зөөврийн сүлжээний цэг"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Блютүүт модем болгох"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Модем болгох"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Модем болгох &amp; зөөврийн сүлжээний цэг"</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">"Хэрэглэгч: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/arrays.xml b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
new file mode 100644
index 0000000..db21ccc
--- /dev/null
+++ b/packages/SettingsLib/res/values-mr-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"कनेक्ट करत आहे..."</item>
+    <item msgid="515055375277271756">"प्रमाणीकरण करत आहे…"</item>
+    <item msgid="1943354004029184381">"IP पत्ता प्राप्त करत आहे…"</item>
+    <item msgid="4221763391123233270">"कनेक्ट केले"</item>
+    <item msgid="624838831631122137">"निलंबित"</item>
+    <item msgid="7979680559596111948">"डिस्कनेक्ट करत आहे..."</item>
+    <item msgid="1634960474403853625">"डिस्कनेक्ट केले"</item>
+    <item msgid="746097431216080650">"अयशस्वी"</item>
+    <item msgid="6367044185730295334">"अवरोधित"</item>
+    <item msgid="503942654197908005">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वर कनेक्ट केले आहे"</item>
+    <item msgid="1330262655415760617">"निलंबित"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> वरून डिस्कनेक्ट करत आहे…"</item>
+    <item msgid="197508606402264311">"डिस्कनेक्ट केले"</item>
+    <item msgid="8578370891960825148">"अयशस्वी"</item>
+    <item msgid="5660739516542454527">"अवरोधित"</item>
+    <item msgid="1805837518286731242">"तात्पुरते खराब कनेक्शन टाळत आहे"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
new file mode 100644
index 0000000..3a05cb9
--- /dev/null
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्कसाठी स्कॅन करू शकत नाही"</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_network_failure" msgid="2364951338436007124">"IP कॉन्फिगरेशन अयशस्वी"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi कनेक्शन अयशस्वी"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"कोणताही इंटरनेट प्रवेश आढळला नाही, स्वयंचलितपणे रीकनेक्ट करणार नाही."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi सहाय्यक द्वारे कनेक्ट केले"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्‍ट केले"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s द्वारे उपलब्‍ध"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"कनेक्‍ट केले, इंटरनेट नाही"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"डिस्कनेक्ट केले"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्कनेक्ट करत आहे..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट करीत आहे..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"कनेक्ट केले"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"जोडत आहे…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"कनेक्ट केले (फोन नाही)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"कनेक्ट केले (मीडिया नाही)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"कनेक्ट केलेले आहे (कोणत्याही संदेशामध्ये प्रवेश नाही)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"कनेक्ट केले (फोन किंवा मीडिया नाही)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मीडिया ऑडिओ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"फोन ऑडिओ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"फाइल स्थानांतरण"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"इनपुट डिव्हाइस"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"इंटरनेट प्रवेश"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"संपर्क सामायिकरण"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"संपर्क सामायिकरणासाठी वापरा"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इंटरनेट कनेक्शन सामायिकरण"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"संदेशात प्रवेश"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"सिम प्रवेश"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मीडिया ऑडिओवर कनेक्ट केले"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फोन ऑडिओ वर कनेक्ट केले"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फाईल स्थानांतर सर्व्हरवर कनेक्ट केले"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"नकाशाशी कनेक्ट केले"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP शी कनेक्‍ट केले"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फाइल स्थानांतर सर्व्हरशी कनेक्ट केले नाही"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट डिव्हाइसवर कनेक्ट केले"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इंटरनेट प्रवेशासाठी डिव्हाइसवर कनेक्ट केले"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"डिव्हाइससह स्थानिक इंटरनेट कनेक्शन सामायिक करत आहे"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इंटरनेट प्रवेशासाठी वापरा"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नकाशासाठी वापरा"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM प्रवेशासाठी वापरा"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मीडिया ऑडिओसाठी वापरा"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन ऑडिओसाठी वापरा"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाईल स्थानांतरणासाठी वापरा"</string>
+    <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_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> सह जोडू शकलो नाही."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संप्रेषण करू शकत नाही."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारे जोडणी नाकारली."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"वाय फाय बंद."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"वाय फाय डिस्कनेक्ट झाले."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"वाय फाय एक बार."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"वाय फाय दोन बार."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"वाय फाय तीन बार."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"वाय फाय सिग्नल संपूर्ण आहे."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"काढलेले अॅप्स"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"काढलेले अॅप्स आणि वापरकर्ते"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेदरिंग"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्पॉट"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटुथ टेदरिंग"</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="8101244883654409696">"कार्य प्रोफाईल"</string>
+    <string name="user_guest" msgid="8475274842845401871">"अतिथी"</string>
+    <string name="unknown" msgid="1592123443519355854">"अज्ञात"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"वापरकर्ता: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/arrays.xml b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
new file mode 100644
index 0000000..15cd7ba
--- /dev/null
+++ b/packages/SettingsLib/res/values-ms-rMY/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Mengimbas..."</item>
+    <item msgid="8513729475867537913">"Menyambung..."</item>
+    <item msgid="515055375277271756">"Mengesahkan..."</item>
+    <item msgid="1943354004029184381">"Mendapatkan alamat IP..."</item>
+    <item msgid="4221763391123233270">"Disambungkan"</item>
+    <item msgid="624838831631122137">"Digantung"</item>
+    <item msgid="7979680559596111948">"Memutuskan sambungan..."</item>
+    <item msgid="1634960474403853625">"Diputuskan sambungan"</item>
+    <item msgid="746097431216080650">"Tidak berjaya"</item>
+    <item msgid="6367044185730295334">"Disekat"</item>
+    <item msgid="503942654197908005">"Mengelakkan sambungan lemah buat sementara"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Mengimbas..."</item>
+    <item msgid="355508996603873860">"Menyambung kepada <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Mengesahkan dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Disambungkan kepada <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Digantung"</item>
+    <item msgid="7698638434317271902">"Memutuskan sambungan dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Diputuskan sambungan"</item>
+    <item msgid="8578370891960825148">"Tidak berjaya"</item>
+    <item msgid="5660739516542454527">"Disekat"</item>
+    <item msgid="1805837518286731242">"Mengelakkan sambungan lemah buat sementara"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
new file mode 100644
index 0000000..b917ad0
--- /dev/null
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak boleh mengimbas untuk rangkaian"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Tiada"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Dinyahdayakan"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kegagalan Sambungan WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Masalah pengesahan"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Tidak dalam liputan"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Tiada Akses Internet Dikesan, tidak akan menyambung secara automatik."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Diselamatkan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Disambungkan melalui Pembantu Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Disambungkan melalui %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Tersedia melalui %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Disambungkan, tiada Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Diputuskan sambungan"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Memutuskan sambungan..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Menyambung..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Bersambung"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Memasangkan..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Disambungkan (tiada telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Disambungkan (tiada media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Disambungkan (tiada akses mesej)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Disambungkan (tiada telefon atau media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio media"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio telefon"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Pemindahan fail"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Peranti input"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Akses Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Perkongsian kenalan"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Gunakan untuk perkongsian kenalan"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Perkongsian sambungan Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Akses Mesej"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Akses SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Disambungkan ke audio media"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Disambungkan ke audio telefon"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Bersambung ke pelayan pemindahan fail"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Disambungkan ke peta"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Disambungkan ke SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Tidak bersambung kepada pelayan pemindahan fail"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Disambungkan ke peranti input"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Sbg ke pranti utk aks Int"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kgsi sbgn Int dgn peranti"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gunakan untuk akses Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gunakan untuk peta"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gunakan untuk akses SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gunakan untuk audio media"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gunakan untuk audio telefon"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gunakan untuk pemindahan fail"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gunakan untuk input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Jadikan pasangan"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"JADIKAN PASANGAN"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Batal"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Berpasangan memberi anda akses kepada kenalan dan sejarah panggilan apabila disambungkan."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Tidak dapat berpasangan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Tidak dapat berpasangan dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kerana PIN atau kunci laluan yang salah."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Tidak boleh berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pasangan ditolak oleh <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi dimatikan."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi diputuskan sambungannya."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi satu bar."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi dua bar."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi tiga bar."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Isyarat Wi-Fi penuh."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apl dialih keluar"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apl dan pengguna yang dialih keluar"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Penambatan USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Titik panas mudah alih"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Penambatan Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Penambatan"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Liputan tambatan &amp; mudah alih"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil kerja"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Tetamu"</string>
+    <string name="unknown" msgid="1592123443519355854">"Tidak diketahui"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Pengguna: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Beberapa lalai ditetapkan"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Tiada lalai ditetapkan"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/arrays.xml b/packages/SettingsLib/res/values-my-rMM/arrays.xml
new file mode 100644
index 0000000..82f2ded
--- /dev/null
+++ b/packages/SettingsLib/res/values-my-rMM/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"ချိတ်ဆက်နေသည်"</item>
+    <item msgid="515055375277271756">"စစ်မှန်ကြောင်းအတည်ပြုနေသည်"</item>
+    <item msgid="1943354004029184381">"အိုင်ပီလိပ်စာရယူနေသည်"</item>
+    <item msgid="4221763391123233270">"ဆက်သွယ်ထားပြီး"</item>
+    <item msgid="624838831631122137">"ဆိုင်းငံ့ထားသည်"</item>
+    <item msgid="7979680559596111948">"အဆက်အသွယ်ဖြတ်တောက်နေသည်"</item>
+    <item msgid="1634960474403853625">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</item>
+    <item msgid="746097431216080650">"မအောင်မြင်ပါ"</item>
+    <item msgid="6367044185730295334">"ပိတ်ထားသည်"</item>
+    <item msgid="503942654197908005">"နှေးကွေးသောဆက်သွယ်မှုကို ယာယီရှောင်ရှားထားသည်"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> နှင့် ဆက်သွယ်ထားပြီး"</item>
+    <item msgid="1330262655415760617">"ဆိုင်းငံ့ထားသည်"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>မှ ဆက်သွယ်မှုဖြတ်တောက်သွားသည်"</item>
+    <item msgid="197508606402264311">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</item>
+    <item msgid="8578370891960825148">"မအောင်မြင်ပါ"</item>
+    <item msgid="5660739516542454527">"ပိတ်ထားသည်"</item>
+    <item msgid="1805837518286731242">"နှေးကွေးသောဆက်သွယ်မှုကို ယာယီရှောင်ရှားထားသည်"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
new file mode 100644
index 0000000..56adf2d
--- /dev/null
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ကွန်ယက်များကို စကင်မလုပ်နိုင်ပါ"</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_network_failure" msgid="2364951338436007124">"IP ပြုပြင်ခြင်း မအောင်မြင်ပါ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ချိတ်ဆက်မှု မအောင်မြင်ပါ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"စစ်မှန်ကြောင်းအတည်ပြုရန်၌ ပြသနာရှိခြင်း"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"စက်ကွင်းထဲတွင် မဟုတ်ပါ"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"မည်သည့် အင်တာနက်မျှမရှိပါ၊ အလိုအလျောက် ပြန်လည်မချိတ်ဆက်ပါ။"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> မှသိမ်းဆည်းခဲ့သည်"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"ကြိုးမဲ့ကူညီသူမှတဆင့် ချိတ်ဆက်၏"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ချိတ်ဆက်မှုပြတ်တောက်သည်"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"အဆက်အသွယ်ဖြတ်တောက်သည်"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"ချိတ်ဆက်နေသည်"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"ချိတ်ဆက်ထားပြီး"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"တွဲချိတ်ပါ"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"ချိတ်ဆက်ထားပြီး (ဖုန်းမရှိ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ချိတ်ဆက်ထားပြီး (မီဒီယာမရှိ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ချိတ်ဆက်မိသည် (သတင်းရယူမှုမရှိ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ချိတ်ဆက်ပြီး (ဖုန်း သို့ မီဒီယာမဟုတ်ပါ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"မီဒီယာ အသံ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ဖုန်းအသံ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ဖိုင်လွဲပြောင်းခြင်း"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ထည့်သွင်းသော စက်"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"အင်တာနက်ချိတ်ဆက်ခြင်း"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"အဆက်အသွယ်ကို မျှဝေရန်"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"အဆက်အသွယ်ကို မျှဝေရန် အတွက် သုံးရန်"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"အင်တာနက်ဆက်သွယ်မှု မျှဝေခြင်း"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"သတင်းရယူမှု"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM အသုံးပြုခြင်း"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"မီဒီယာအသံအား ချိတ်ဆက်ရန်"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ဖုန်းအသံအား ချိတ်ဆက်ရန်"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ဖိုင်လွှဲပြောင်းမည့်ဆာဗာနှင့် ချိတ်ဆက်ထားပြီး"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"မြေပုံနှင့် ချိတ်ဆက်ရန်"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP သို့ချိတ်ဆက်ထားသည်"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ဖိုင်လွှဲပြောင်းမည့်ဆာဗာနှင့် ချိတ်ဆက်မထားပါ"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ထည့်သွင်းထားသောစက်ကို ချိတ်ဆက်မည်"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"အင်တာနက်ဆက်သွယ်မှုရရန် စက်နှင်ချိတ်ဆက်မည်"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"စက်နှင့် ပုံမှန်အင်တာနက်ဆက်သွယ်မှုအား မျှဝေစေရန်"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"အင်တာနက်ချိတ်ဆက်ရန်အသုံးပြုသည်"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"မြေပုံအတွက်သုံးရန်"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM အသုံးပြုမှုအတွက် အသုံးပြုမည်"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"မီဒီယာအသံအတွက်အသုံးပြုရန်"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ဖုန်းအသံအားအသုံးပြုရန်"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ဖိုင်လွဲပြောင်းရန်အတွက်အသုံးပြုရန်"</string>
+    <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_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>နှင့် တွဲချိတ်မရပါ။"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်ဆက်သွယ်မရပါ"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>နှင့်တွဲချိတ်ရန် ပယ်ချခံရသည်"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"ဝိုင်ဖိုင် မရှိ"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"ဝိုင်ဖိုင် ချိတ်ဆက်ထားမှု မရှိပါ"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"ဝိုင်ဖိုင် ၁ ဘားရှိ"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"ဝိုင်ဖိုင် ၂ ဘား"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"ဝိုင်ဖိုင် ၃ ဘား"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"ဝိုင်ဖိုင် အပြည့်ရှိ"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android စနစ်"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ဖယ်ရှားထားသော အပ်ပလီကေးရှင်းများ"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ဖယ်ရှားထားသော အပလီကေးရှင်းနှင့် သုံးစွဲသူများ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USBမှတဆင့်ချိတ်ဆက်ခြင်း"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ရွေ့လျားနိုင်သောဟော့စပေါ့"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ဘလူးတုသ်တဆင့်ပြန်ချိတ်ဆက်"</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="8101244883654409696">"အလုပ် ပရိုဖိုင်"</string>
+    <string name="user_guest" msgid="8475274842845401871">"ဧည့်သည်"</string>
+    <string name="unknown" msgid="1592123443519355854">"အကြောင်းအရာ မသိရှိ"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"သုံးစွဲသူ၊ <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-nb/arrays.xml b/packages/SettingsLib/res/values-nb/arrays.xml
new file mode 100644
index 0000000..af7c0b1
--- /dev/null
+++ b/packages/SettingsLib/res/values-nb/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skanner ..."</item>
+    <item msgid="8513729475867537913">"Kobler til …"</item>
+    <item msgid="515055375277271756">"Autentiserer ..."</item>
+    <item msgid="1943354004029184381">"Henter IP-adresse …"</item>
+    <item msgid="4221763391123233270">"Tilkoblet"</item>
+    <item msgid="624838831631122137">"Avsluttet"</item>
+    <item msgid="7979680559596111948">"Kobler fra ..."</item>
+    <item msgid="1634960474403853625">"Frakoblet"</item>
+    <item msgid="746097431216080650">"Mislyktes"</item>
+    <item msgid="6367044185730295334">"Blokkert"</item>
+    <item msgid="503942654197908005">"Unngår dårlig tilkobling midlertidig"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skanner ..."</item>
+    <item msgid="355508996603873860">"Kobler til <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="554971459996405634">"Autentiserer med <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="7928343808033020343">"Henter IP-adresse fra <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="8937994881315223448">"Koblet til <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Avsluttet"</item>
+    <item msgid="7698638434317271902">"Kobler fra <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="197508606402264311">"Frakoblet"</item>
+    <item msgid="8578370891960825148">"Mislyktes"</item>
+    <item msgid="5660739516542454527">"Blokkert"</item>
+    <item msgid="1805837518286731242">"Unngår dårlig tilkobling midlertidig"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
new file mode 100644
index 0000000..0c0d66f
--- /dev/null
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan ikke søke etter nettverk"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Lagret"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Slått av"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurasjonsfeil"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-tilkoblingsfeil"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Utenfor område"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen Internett-tilgang ble funnet. Kan ikke koble til på nytt automatisk."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Lagret av <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Koblet til via en Wi-Fi-assistent"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Tilkoblet via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Tilgjengelig via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Tilkoblet – ingen Internett-forbindelse"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Frakoblet"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Kobler fra…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Kobler til…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Tilkoblet"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Sammenkobles …"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Tilkobling (ingen telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Tilkoblet (ingen medier)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Tilkoblet (ingen meldingstilgang)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Tilkoblet (ingen telefon eller media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medielyd"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefonlyd"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filoverføring"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Inndataenhet"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internett-tilgang"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktdeling"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Bruk til kontaktdeling"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Deling av Internett-tilkobling"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Meldingstilgang"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Tilgang til SIM-kortet"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Koblet til medielyd"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Koblet til telefonlyd"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Koblet til tjener for filoverføring"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Koblet til kart"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Koblet til SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ikke koblet til tjener for filoverføring"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Koblet til inndataenhet"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Koblet til enhet for Internett-tilgang"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Deler lokal Internett-tilkobling med enhet"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Bruk for Internett-tilgang"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Bruk for kart"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Bruk for tilgang til SIM-kortet"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Bruk for medielyd"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Bruk for telefonlyd"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Bruk til filoverføring"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Bruk for inndata"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sammenkoble"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOBLE"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Med sammenkobling får den andre enheten tilgang til kontaktene og anropsloggen din når den er tilkoblet."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kan ikke koble til <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kan ikke koble til <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grunn av feil personlig kode eller passord."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan ikke kommunisere med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> avslo paring."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi er av."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi er frakoblet."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi-signal med én stolpe."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi-signal med to stolper."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi-signal med tre stolper."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi-signalet er ved full styrke."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android-operativsystem"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Fjernede apper"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Fjernede apper og brukere"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-internettdeling"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Flyttbar trådløs sone"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-internettdeling"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Internettdeling"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Nettdeling og trådløs sone"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Jobbprofil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gjest"</string>
+    <string name="unknown" msgid="1592123443519355854">"Ukjent"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Bruker:<xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Noen standardvalg er angitt"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Ingen standardvalg er angitt"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/arrays.xml b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
new file mode 100644
index 0000000..7cb9ceb
--- /dev/null
+++ b/packages/SettingsLib/res/values-ne-rNP/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"जडान हुँदै..."</item>
+    <item msgid="515055375277271756">"प्रमाणित गर्दै ..."</item>
+    <item msgid="1943354004029184381">"IP ठेगाना पत्ता लगाउँदै ..."</item>
+    <item msgid="4221763391123233270">"जडान गरिएको"</item>
+    <item msgid="624838831631122137">"निलम्बित"</item>
+    <item msgid="7979680559596111948">"विच्छेदन गर्दै..."</item>
+    <item msgid="1634960474403853625">"विच्छेदन भएको"</item>
+    <item msgid="746097431216080650">"असफल"</item>
+    <item msgid="6367044185730295334">"रोक्का गरियो"</item>
+    <item msgid="503942654197908005">"अस्थायी रूपमा कमजोर जडान बेवास्ता गर्दै"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>सँग जडित"</item>
+    <item msgid="1330262655415760617">"निलम्बित"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>बाट विच्छेदन गर्दै..."</item>
+    <item msgid="197508606402264311">"विच्छेदन भएको"</item>
+    <item msgid="8578370891960825148">"असफल"</item>
+    <item msgid="5660739516542454527">"रोकियो"</item>
+    <item msgid="1805837518286731242">"अस्थायी रूपमा कमजोर जडान हटाइँदै"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
new file mode 100644
index 0000000..4ca6860
--- /dev/null
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"सञ्जालका लागि स्क्यान गर्न सक्दैन"</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_network_failure" msgid="2364951338436007124">"IP विन्यास असफल"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"वाईफाई जडान असफल"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"प्रमाणीकरण समस्या"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"दायराभित्र छैन"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"कुनै इन्टरनेट पहुँच पाईएन, स्वचालित रूपमा पुन: जडान छैन।"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा सुरक्षित गरियो"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi-Fi सहायक द्वारा जोडिएको"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s मार्फत जडित"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s मार्फत उपलब्ध"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"जडित, इन्टरनेट चलेको छैन"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"विच्छेदन गरियो"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"जडान हटाइँदै ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"जडान हुँदै..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"जडान गरिएको"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"जोडा बाँध्दै..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"जडान (कुनै फोन छैन)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"जडित (कुनै पनि मिडिया छैन)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"जडित छ (सन्देशमा पहुँच छैन)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"जडित (फोन वा मिडिया छैन)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"मिडिया अडियो"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"फोन अडियो"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"फाइल स्थानान्तरण"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"इनपुट उपकरण"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"इन्टरनेट पहुँच"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"सम्पर्क साझेदारी"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"सम्पर्क साझेदारीका लागि प्रयोग"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"इन्टरनेट जडान साझेदारी गर्दै"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"सन्देश पहुँच"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM पहुँच"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"मिडिया अडियोसँग जडित"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"फोन अडियोमा जडान गरियो"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"फाइल ट्रान्सफर सर्भरमा जडान गरियो"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"नक्सासँग जडित"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP मा जडित"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"फाइल ट्रान्सफर सर्भरसँग जडान गरिएको छैन"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"इनपुट उपकरणसँग जोडिएको छ"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"इन्टरनेट पहुँचका लागि उपकरणसँग जडित"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"उपकरणसँग स्थानीय इन्टरनेट जडान साझेदारी गर्दै"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"इन्टर्नेट पहुँचका लागि प्रयोग गर्नुहोस्"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"नक्साको लागि प्रयोग गर्नुहोस्"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM मा पहुँचका लागि प्रयोग गर्नुहोस्"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"मिडिया अडियोका लागि प्रयोग गर्नुहोस्"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"फोन अडियोको लागि प्रयोग गर्नुहोस्"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"फाइल ट्रान्सफरका लागि प्रयोग गर्नुहोस्"</string>
+    <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_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 वा पासकिका कारण सँग जोडा बाँध्न सक्दैन।"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> सँग कुराकानी हुन सक्दैन।"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारा जोडा बाँध्ने कार्य अस्वीकृत"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi बन्द।"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi जडान विच्छेद भयो।"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi एक पट्टि।"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi दुई पट्टि।"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi तीन बारहरू।"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"पूर्ण Wi-Fi सिंग्नल।"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"एन्ड्रोइड OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"हटाइएका अनुप्रयोगहरू"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"अनुप्रयोगहरू र प्रयोगकर्ताहरू हटाइयो।"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेथर गर्दै"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हटस्पट"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लुटुथ टेथर गर्दै"</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="8101244883654409696">"कार्य प्रोफाइल"</string>
+    <string name="user_guest" msgid="8475274842845401871">"अतिथि"</string>
+    <string name="unknown" msgid="1592123443519355854">"अज्ञात"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"प्रयोगकर्ता: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-nl/arrays.xml b/packages/SettingsLib/res/values-nl/arrays.xml
new file mode 100644
index 0000000..ab72b67
--- /dev/null
+++ b/packages/SettingsLib/res/values-nl/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Scannen..."</item>
+    <item msgid="8513729475867537913">"Verbinding maken..."</item>
+    <item msgid="515055375277271756">"Verifiëren..."</item>
+    <item msgid="1943354004029184381">"IP-adres ophalen…"</item>
+    <item msgid="4221763391123233270">"Verbonden"</item>
+    <item msgid="624838831631122137">"Opgeschort"</item>
+    <item msgid="7979680559596111948">"Verbinding verbreken..."</item>
+    <item msgid="1634960474403853625">"Verbinding verbroken"</item>
+    <item msgid="746097431216080650">"Mislukt"</item>
+    <item msgid="6367044185730295334">"Geblokkeerd"</item>
+    <item msgid="503942654197908005">"Slechte verbinding tijdelijk vermijden"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Scannen..."</item>
+    <item msgid="355508996603873860">"Verbinding maken met <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Verifiëren met <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"IP-adres ophalen van <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Verbonden met <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Opgeschort"</item>
+    <item msgid="7698638434317271902">"Verbinding verbreken met <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Verbinding verbroken"</item>
+    <item msgid="8578370891960825148">"Mislukt"</item>
+    <item msgid="5660739516542454527">"Geblokkeerd"</item>
+    <item msgid="1805837518286731242">"Slechte verbinding tijdelijk vermijden"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
new file mode 100644
index 0000000..cae3e92
--- /dev/null
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Kan niet scannen naar netwerken"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Geen"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Opgeslagen"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Uitgeschakeld"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-configuratie mislukt"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wifi-verbinding mislukt"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Authenticatieprobleem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Niet binnen bereik"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Geen internettoegang gevonden. Er wordt niet automatisch opnieuw verbinding gemaakt."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Opgeslagen door <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Verbonden via wifi-assistent"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Verbonden via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Beschikbaar via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Verbonden, geen internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Verbinding verbroken"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Verbinding verbreken..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Verbinding maken..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Verbonden"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Koppelen..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Gekoppeld (geen telefoon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Gekoppeld (geen media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Verbonden (geen toegang tot berichten)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Gekoppeld (geen telefoon of media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media-audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefoonaudio"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Bestandsoverdracht"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Invoerapparaat"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internettoegang"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Contacten delen"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Gebruiken voor contacten delen"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internetverbinding delen"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Toegang tot berichten"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Sim-toegang"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Verbonden met audio van medium"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Verbonden met audio van telefoon"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Verbonden met server voor bestandsoverdracht"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Verbonden met kaart"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Verbonden via SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Niet verbonden met server voor bestandsoverdracht"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Verbonden met invoerapparaat"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Verbonden met apparaat voor internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Lokale internetverbinding delen met apparaat"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gebruik voor internettoegang"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gebruiken voor kaart"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gebruiken voor sim-toegang"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gebruiken voor audio van medium"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Gebruiken voor audio van telefoon"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Gebruiken voor bestandsoverdracht"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gebruiken voor invoer"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Koppelen"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPELEN"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Annuleren"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Koppelen verleent toegang tot je contacten en oproepgeschiedenis wanneer de apparaten zijn verbonden."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Kan niet koppelen aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Kan niet koppelen aan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> vanwege een onjuiste pincode of toegangscode."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Kan niet communiceren met <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Koppeling geweigerd door <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi: uitgeschakeld."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi-verbinding verbroken."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi: één streepje."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi: twee streepjes."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi: drie streepjes."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifii-signaal is op volledige sterkte."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android-besturingssysteem"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Verwijderde apps"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Verwijderde apps en gebruikers"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Draagbare hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth-tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering en draagbare hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Werkprofiel"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gast"</string>
+    <string name="unknown" msgid="1592123443519355854">"Onbekend"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Gebruiker: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Enkele standaardwaarden ingesteld"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Geen standaardwaarden ingesteld"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/arrays.xml b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
new file mode 100644
index 0000000..a03f17e
--- /dev/null
+++ b/packages/SettingsLib/res/values-pa-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="515055375277271756">"ਪ੍ਰਮਾਣਿਤ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="1943354004029184381">"IP ਪਤਾ ਪ੍ਰਾਪਤ ਕਰ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="4221763391123233270">"ਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="624838831631122137">"ਮੁਅੱਤਲ ਕੀਤਾ"</item>
+    <item msgid="7979680559596111948">"ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</item>
+    <item msgid="1634960474403853625">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="746097431216080650">"ਅਸਫਲ"</item>
+    <item msgid="6367044185730295334">"ਬਲੌਕ ਕੀਤਾ"</item>
+    <item msgid="503942654197908005">"ਅਸਥਾਈ ਤੌਰ ਤੇ ਖ਼ਰਾਬ ਕਨੈਕਸ਼ਨ ਤੋਂ ਬਚਣ ਲਈ"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="1330262655415760617">"ਮੁਅੱਤਲ ਕੀਤਾ"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ਤੋਂ ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</item>
+    <item msgid="197508606402264311">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</item>
+    <item msgid="8578370891960825148">"ਅਸਫਲ"</item>
+    <item msgid="5660739516542454527">"ਬਲੌਕ ਕੀਤਾ"</item>
+    <item msgid="1805837518286731242">"ਅਸਥਾਈ ਤੌਰ ਤੇ ਖ਼ਰਾਬ ਕਨੈਕਸ਼ਨ ਤੋਂ ਬਚਣ ਲਈ"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
new file mode 100644
index 0000000..b319663
--- /dev/null
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ਨੈਟਵਰਕਾਂ ਲਈ ਸਕੈਨ ਨਹੀਂ ਕਰ ਸਕਦਾ"</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_network_failure" msgid="2364951338436007124">"IP ਕੌਂਫਿਗਰੇਸ਼ਨ ਅਸਫਲਤਾ"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi ਕਨੈਕਸ਼ਨ ਅਸਫਲਤਾ"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ਪ੍ਰਮਾਣੀਕਰਨ ਸਮੱਸਿਆ"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"ਰੇਂਜ ਵਿੱਚ ਨਹੀਂ ਹੈ"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ਕੋਈ ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਨਹੀਂ ਮਿਲੀ, ਆਟੋਮੈਟਿਕਲੀ ਰੀਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ ਜਾਏਗਾ।"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਕੀਤਾ"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi ਸਹਾਇਕ ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈਟ ਨਹੀਂ"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ਡਿਸਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"ਡਿਸਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"ਕਨੈਕਟ ਕਰ ਰਿਹਾ ਹੈ…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"ਪੇਅਰ ਕਰ ਰਿਹਾ ਹੈ…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਫੋਨ ਨਹੀਂ)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਮੀਡੀਆ ਨਹੀਂ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਸੁਨੇਹਾ ਪਹੁੰਚ ਨਹੀਂ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"ਕਨੈਕਟ ਕੀਤਾ (ਕੋਈ ਫੋਨ ਜਾਂ ਮੀਡੀਆ ਨਹੀਂ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"ਮੀਡੀਆ ਔਡੀਓ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ਫੋਨ ਔਡੀਓ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ਇਨਪੁਟ ਡਿਵਾਈਸ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ਇੰਟਰਨੈਟ ਪਹੁੰਚ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"ਸੰਪਰਕ ਸ਼ੇਅਰਿੰਗ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"ਸੰਪਰਕ ਸ਼ੇਅਰਿੰਗ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਸ਼ੇਅਰਿੰਗ"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"ਸੁਨੇਹਾ ਪਹੁੰਚ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ਪਹੁੰਚ"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"ਮੀਡੀਆ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ਫੋਨ ਔਡੀਓ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਸਰਵਰ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"ਨਕਸ਼ੇ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਸਰਵਰ ਨਾਲ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ਇਨਪੁਟ ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਲਈ ਡਿਵਾਈਸ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"ਡਿਵਾਈਸ ਨਾਲ ਸਥਾਨਕ ਇੰਟਰਨੈਟ ਕਨੈਕਸ਼ਨ ਸ਼ੇਅਰ ਕਰ ਰਿਹਾ ਹੈ"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ਇੰਟਰਨੈਟ ਪਹੁੰਚ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ਨਕਸ਼ੇ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ਪਹੁੰਚ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ਮੀਡੀਆ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ਫੋਨ ਔਡੀਓ ਲਈ ਵਰਤੋ"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ਫਾਈਲ ਟ੍ਰਾਂਸਫਰ ਲਈ ਵਰਤੋ"</string>
+    <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_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">"ਇੱਕ ਗ਼ਲਤ PIN ਜਾਂ ਪਾਸਕੁੰਜੀ ਦੇ ਕਾਰਨ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਪੇਅਰ ਨਹੀਂ ਕਰ ਸਕਿਆ।"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਨਾਲ ਸੰਚਾਰ ਨਹੀਂ ਕਰ ਸਕਦਾ।"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"ਪੇਅਰਿੰਗ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਵੱਲੋਂ ਰੱਦ ਕੀਤੀ ਗਈ।"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi ਬੰਦ।"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi ਡਿਸਕਨੈਕਟ ਕੀਤਾ।"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi ਇੱਕ ਬਾਰ।"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi ਦੋ ਬਾਰ।"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi ਤਿੰਨ ਬਾਰ।"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi ਸਿਗਨਲ ਪੂਰਾ।"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ਹਟਾਏ ਗਏ ਐਪਸ"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ਹਟਾਏ ਗਏ ਐਪਸ ਅਤੇ ਉਪਭੋਗਤਾ"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ਟੀਥਰਿੰਗ"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ਪੋਰਟੇਬਲ ਹੌਟਸਪੌਟ"</string>
+    <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">"ਟੀਥਰਿੰਗ &amp; ਪੋਰਟੇਬਲ ਹੌਟਸਪੌਟ"</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">"ਉਪਭੋਗਤਾ: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-pl/arrays.xml b/packages/SettingsLib/res/values-pl/arrays.xml
new file mode 100644
index 0000000..d2cbe24
--- /dev/null
+++ b/packages/SettingsLib/res/values-pl/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Trwa skanowanie..."</item>
+    <item msgid="8513729475867537913">"Trwa łączenie..."</item>
+    <item msgid="515055375277271756">"Trwa uwierzytelnianie..."</item>
+    <item msgid="1943354004029184381">"Uzyskiwanie adresu IP..."</item>
+    <item msgid="4221763391123233270">"Połączono"</item>
+    <item msgid="624838831631122137">"Zawieszona"</item>
+    <item msgid="7979680559596111948">"Trwa rozłączanie..."</item>
+    <item msgid="1634960474403853625">"Rozłączona"</item>
+    <item msgid="746097431216080650">"Niepowodzenie"</item>
+    <item msgid="6367044185730295334">"Zablokowana"</item>
+    <item msgid="503942654197908005">"Tymczasowo, by uniknąć połączenia o niskiej jakości"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Trwa skanowanie..."</item>
+    <item msgid="355508996603873860">"Trwa łączenie z siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Trwa uwierzytelnianie w sieci <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Uzyskiwanie adresu IP z sieci <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Połączono z siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Zawieszona"</item>
+    <item msgid="7698638434317271902">"Trwa rozłączanie z siecią <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Rozłączona"</item>
+    <item msgid="8578370891960825148">"Niepowodzenie"</item>
+    <item msgid="5660739516542454527">"Zablokowana"</item>
+    <item msgid="1805837518286731242">"Tymczasowo, by uniknąć połączenia o niskiej jakości"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
new file mode 100644
index 0000000..7858201
--- /dev/null
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nie można wyszukać sieci."</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Brak"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Zapisana"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Wyłączona"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Błąd konfiguracji IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Błąd połączenia Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem z uwierzytelnianiem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Poza zasięgiem"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nie wykryto dostępu do internetu. Nie można automatycznie przywrócić połączenia."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Zapisane przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Połączono przez Asystenta Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Połączono przez %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Dostępne przez %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Połączono, brak internetu"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Rozłączona"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Rozłączanie..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Łączenie..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Połączony"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Parowanie..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Połączono (bez telefonu)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Połączono (bez multimediów)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Połączono (brak dostępu do wiadomości)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Połączono (bez telefonu ani multimediów)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Dźwięk multimediów"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Dźwięk telefonu"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Przesyłanie pliku"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Urządzenie wejściowe"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Dostęp do internetu"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Udostępnianie kontaktów"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Używaj do udostępniania kontaktów"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Udostępnianie połączenia internetowego"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Dostęp do wiadomości"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Dostęp do karty SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Połączono z funkcją audio multimediów"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Połączono z funkcją audio telefonu"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Połączono z serwerem transferu plików"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Połączono z mapą"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Połączono z PDU"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Brak połączenia z serwerem transferu plików"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Podłączono do urządzenia wejściowego"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Połączone w celu dostępu do internetu"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Udostępnianie połączenia internetowego"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Użyj na potrzeby dostępu do internetu"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Używaj dla mapy"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Używaj, by uzyskać dostęp do karty SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Użyj dla funkcji audio multimediów"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Użyj dla funkcji audio telefonu"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Użyj do transferu plików"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Użyj do wprowadzania"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Sparuj"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SPARUJ"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anuluj"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Parowanie spowoduje przyznanie dostępu do historii połączeń i Twoich kontaktów w trakcie połączenia."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nie można sparować z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nie można sparować z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ze względu na błędny kod PIN lub klucz."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nie można skomunikować się z urządzeniem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Powiązanie odrzucone przez urządzenie <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi wyłączone."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi odłączone."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: jeden pasek."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: dwa paski."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: trzy paski."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi: pełna moc sygnału."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"System operacyjny Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Usunięte aplikacje"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Usunięte aplikacje i użytkownicy"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering przez USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Przenośny punkt dostępu"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering przez Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering i punkt dostępu"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil do pracy"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gość"</string>
+    <string name="unknown" msgid="1592123443519355854">"Nieznana"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Użytkownik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Część ustawień domyślnych"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Brak ustawień domyślnych"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/arrays.xml b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
new file mode 100644
index 0000000..cea70da
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt-rBR/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Procurando…"</item>
+    <item msgid="8513729475867537913">"Conectando..."</item>
+    <item msgid="515055375277271756">"Autenticando..."</item>
+    <item msgid="1943354004029184381">"Obtendo endereço IP…"</item>
+    <item msgid="4221763391123233270">"Conectado"</item>
+    <item msgid="624838831631122137">"Suspenso"</item>
+    <item msgid="7979680559596111948">"Desconectando…"</item>
+    <item msgid="1634960474403853625">"Desconectado"</item>
+    <item msgid="746097431216080650">"Falha"</item>
+    <item msgid="6367044185730295334">"Bloqueado"</item>
+    <item msgid="503942654197908005">"Temporariamente evitando uma conexão ruim"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Procurando…"</item>
+    <item msgid="355508996603873860">"Conectando-se a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autenticando com a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtendo endereço IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspenso"</item>
+    <item msgid="7698638434317271902">"Desconectando da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desconectado"</item>
+    <item msgid="8578370891960825148">"Falha"</item>
+    <item msgid="5660739516542454527">"Bloqueado"</item>
+    <item msgid="1805837518286731242">"Temporariamente evitando uma conexão ruim"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..93c4d10
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar a existência de redes"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Salva"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectada, sem Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Conectando..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pareando…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectado (sem telefone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sem mídia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sem acesso a mensagens)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sem telefone ou mídia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio da mídia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Áudio do telefone"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência de arquivo"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acesso à Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartilhamento de contatos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usar para compartilhamento de contatos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartilhamento de conexão à Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acesso a mensagens"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao áudio da mídia"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferência de arquivo"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectado ao mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não está conectado ao servidor de transferência de arquivo"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acesso à Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compart. conexão local de Intern. com disp."</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acesso à Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parear"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Duas barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Três barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Sinal Wi-Fi cheio."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operacional Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apps removidos"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apps e usuários removidos"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ponto de acesso portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering e acesso portátil"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil de trabalho"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Convidado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconhecido"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuário: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Alguns padrões definidos"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nenhum padrão definido"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
new file mode 100644
index 0000000..37bd52a
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"A procurar..."</item>
+    <item msgid="8513729475867537913">"A ligar..."</item>
+    <item msgid="515055375277271756">"A autenticar..."</item>
+    <item msgid="1943354004029184381">"A obter endereço IP..."</item>
+    <item msgid="4221763391123233270">"Ligado"</item>
+    <item msgid="624838831631122137">"Suspenso"</item>
+    <item msgid="7979680559596111948">"A desligar..."</item>
+    <item msgid="1634960474403853625">"Desligado"</item>
+    <item msgid="746097431216080650">"Sem sucesso"</item>
+    <item msgid="6367044185730295334">"Bloqueado"</item>
+    <item msgid="503942654197908005">"A evitar temporariamente uma ligação fraca"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"A procurar..."</item>
+    <item msgid="355508996603873860">"A ligar a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"A autenticar com <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"A obter endereço IP de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Ligado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspenso"</item>
+    <item msgid="7698638434317271902">"A desligar de <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desligado"</item>
+    <item msgid="8578370891960825148">"Sem sucesso"</item>
+    <item msgid="5660739516542454527">"Bloqueado"</item>
+    <item msgid="1805837518286731242">"A evitar temporariamente uma ligação fraca"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..e947352
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar redes"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Guardada"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de ligação Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detetado; não será efetuada uma nova ligação automaticamente."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Guardada por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Ligado através do Assistente de Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Ligado através de %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível através de %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ligado, sem Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desligado"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"A desligar..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"A ligar..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Ligado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"A emparelhar..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ligado (sem telefone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ligado (sem multimédia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ligado (sem acesso a mensagens)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ligado (sem telefone ou multimédia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio de multimédia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Áudio do telemóvel"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência do ficheiro"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acesso à internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Partilha de contactos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utilizar para a partilha de contactos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Partilha da ligação à internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acesso a mensagens"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso ao SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ligado ao áudio de multimédia"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ligado ao áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ligado ao servidor de transferência de ficheiros"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Ligado ao mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ligado ao SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não ligado ao servidor de transferência de ficheiros"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ligado a um dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ligado ao aparelho para acesso à internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"A partilhar a ligação à internet local com o aparelho"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizar para acesso à internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizar para o mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Utilizar para acesso ao SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizar para áudio de multimédia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizar para áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizar para transferência de ficheiros"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizar para entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Par"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SINCRONIZAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"A sincronização concede acesso aos seus contactos e ao histórico de chamadas quando tem uma ligação estabelecida."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível sincronizar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível sincronizar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> devido a PIN ou chave de acesso incorreto."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desativado."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desligado."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Duas barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Três barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Sinal de Wi-Fi completo."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"SO Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicações removidas"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicações e utilizadores removidos"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ligação USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ligação Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Ligação ponto a ponto"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Partilha de Internet"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil de trabalho"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Convidado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconhecido"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Utilizador: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Algumas predefinições definidas"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nenhuma predefinição definida"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt/arrays.xml b/packages/SettingsLib/res/values-pt/arrays.xml
new file mode 100644
index 0000000..cea70da
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Procurando…"</item>
+    <item msgid="8513729475867537913">"Conectando..."</item>
+    <item msgid="515055375277271756">"Autenticando..."</item>
+    <item msgid="1943354004029184381">"Obtendo endereço IP…"</item>
+    <item msgid="4221763391123233270">"Conectado"</item>
+    <item msgid="624838831631122137">"Suspenso"</item>
+    <item msgid="7979680559596111948">"Desconectando…"</item>
+    <item msgid="1634960474403853625">"Desconectado"</item>
+    <item msgid="746097431216080650">"Falha"</item>
+    <item msgid="6367044185730295334">"Bloqueado"</item>
+    <item msgid="503942654197908005">"Temporariamente evitando uma conexão ruim"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Procurando…"</item>
+    <item msgid="355508996603873860">"Conectando-se a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autenticando com a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Obtendo endereço IP da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Conectado a <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspenso"</item>
+    <item msgid="7698638434317271902">"Desconectando da <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Desconectado"</item>
+    <item msgid="8578370891960825148">"Falha"</item>
+    <item msgid="5660739516542454527">"Bloqueado"</item>
+    <item msgid="1805837518286731242">"Temporariamente evitando uma conexão ruim"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
new file mode 100644
index 0000000..93c4d10
--- /dev/null
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Não é possível verificar a existência de redes"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Nenhuma"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Salva"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Desativado"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Falha de configuração de IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Falha de conexão Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema de autenticação"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Fora do alcance"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenhum acesso à Internet detectado. O dispositivo não conectará automaticamente."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Salvas por <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conectado via assistente de Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectado via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponível via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectada, sem Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Desconectado"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Desconectando…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Conectando..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pareando…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectado (sem telefone)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectado (sem mídia)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectado (sem acesso a mensagens)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectado (sem telefone ou mídia)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Áudio da mídia"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Áudio do telefone"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferência de arquivo"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispositivo de entrada"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acesso à Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Compartilhamento de contatos"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Usar para compartilhamento de contatos"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Compartilhamento de conexão à Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acesso a mensagens"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acesso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectado ao áudio da mídia"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectado ao áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectado ao servidor de transferência de arquivo"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectado ao mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectado a SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Não está conectado ao servidor de transferência de arquivo"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectado ao dispositivo de entrada"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectado ao dispositivo para acesso à Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Compart. conexão local de Intern. com disp."</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Usar para acesso à Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Usar para mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Use para acesso SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Usar para áudio de mídia"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Usar para áudio do telefone"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Usado para transferência de arquivo"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Usar para entrada"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parear"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PAREAR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Cancelar"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"O pareamento dá acesso a seus contatos e ao histórico de chamadas quando estiver conectado."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Não foi possível parear com <xliff:g id="DEVICE_NAME">%1$s</xliff:g> por causa de um PIN ou senha incorretos."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Não é possível se comunicar com <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Emparelhamento rejeitado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi desligado."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Uma barra de Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Duas barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Três barras de Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Sinal Wi-Fi cheio."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Sistema operacional Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Apps removidos"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Apps e usuários removidos"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ponto de acesso portátil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering e acesso portátil"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Perfil de trabalho"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Convidado"</string>
+    <string name="unknown" msgid="1592123443519355854">"Desconhecido"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Usuário: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Alguns padrões definidos"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nenhum padrão definido"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-ro/arrays.xml b/packages/SettingsLib/res/values-ro/arrays.xml
new file mode 100644
index 0000000..c4b3b34
--- /dev/null
+++ b/packages/SettingsLib/res/values-ro/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"În curs de scanare..."</item>
+    <item msgid="8513729475867537913">"Se conectează..."</item>
+    <item msgid="515055375277271756">"În curs de autentificare…"</item>
+    <item msgid="1943354004029184381">"Se obține adresa IP..."</item>
+    <item msgid="4221763391123233270">"Conectată"</item>
+    <item msgid="624838831631122137">"Suspendată"</item>
+    <item msgid="7979680559596111948">"În curs de deconectare..."</item>
+    <item msgid="1634960474403853625">"Deconectată"</item>
+    <item msgid="746097431216080650">"Nereușit"</item>
+    <item msgid="6367044185730295334">"Blocat"</item>
+    <item msgid="503942654197908005">"Evitarea temporară a conexiunii slabe"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"În curs de scanare..."</item>
+    <item msgid="355508996603873860">"Se conectează la <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Se autentifică cu <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Se obține adresa IP de la <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Conectat la <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendată"</item>
+    <item msgid="7698638434317271902">"În curs de deconectare de la <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Deconectată"</item>
+    <item msgid="8578370891960825148">"Nereușit"</item>
+    <item msgid="5660739516542454527">"Blocat"</item>
+    <item msgid="1805837518286731242">"Evitarea temporară a conexiunii slabe"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
new file mode 100644
index 0000000..96df0eb
--- /dev/null
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nu se poate scana pentru rețele"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Niciuna"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Salvată"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Dezactivată"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Eroare de configurație IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Eroare de conexiune Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problemă la autentificare"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"În afara ariei de acoperire"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nu s-a detectat acces la internet, nu se va efectua reconectarea automată."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Salvată de <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Conexiune realizată printr-un asistent Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Conectată prin %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Disponibilă prin %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Conectată, fără internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Deconectat"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"În curs de deconectare..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Se conectează..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Conectat"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Se conectează…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Conectat (fără telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Conectat (fără conținut media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Conectat (fără acces la mesaje)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Conectat (fără telefon sau conț. media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Conținut media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Componenta audio a telefonului"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transfer de fișiere"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Dispozitiv de intrare"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Acces internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Acces la Agendă"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Utilizați pentru a permite accesul la Agendă"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Distribuirea conexiunii la internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Acces la mesaje"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Acces la SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Conectat la profilul pentru conținut media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Conectat la componenta audio a telefonului"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Conectat la serverul de transfer de fișiere"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Conectat la hartă"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Conectat la SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Neconectat la serverul de transfer de fișiere"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Conectat la dispozitivul de intrare"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Conectat la dispoz. pt. acces internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Se permite dispoz. acces la internet local"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Utilizați pentru acces internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Utilizați pentru hartă"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Folosiți pentru acces la SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Utilizați pentru profilul pentru conținut media audio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Utilizați pentru componenta audio a telefonului"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Utilizați pentru transferul de fișiere"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Utilizați pentru introducere date"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Asociați"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"CONECTAȚI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anulați"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Asocierea dispozitivelor vă permite accesul la persoanele de contact și la istoricul apelurilor când dispozitivul este conectat."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nu s-a putut împerechea cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nu s-a putut împerechea cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g> din cauza unui cod PIN sau al unei chei de acces incorecte."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nu se poate comunica cu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Împerechere respinsă de <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi dezactivat."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi deconectat."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Semnal Wi-Fi: o bară."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Semnal Wi-Fi: două bare."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Semnal Wi-Fi: trei bare."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Semnal Wi-Fi: complet."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Sistem de operare Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplicații eliminate"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplicaţii și utilizatori eliminaţi"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Tethering prin USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Hotspot portabil"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Tethering prin Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering și hotspot portabil"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profil de serviciu"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Invitat"</string>
+    <string name="unknown" msgid="1592123443519355854">"Necunoscut"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Utilizator: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Unele valori prestabilite sunt configurate"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nu este configurată nicio valoare prestabilită"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-ru/arrays.xml b/packages/SettingsLib/res/values-ru/arrays.xml
new file mode 100644
index 0000000..5f50648
--- /dev/null
+++ b/packages/SettingsLib/res/values-ru/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Подключение..."</item>
+    <item msgid="515055375277271756">"Аутентификация..."</item>
+    <item msgid="1943354004029184381">"Получение IP-адреса..."</item>
+    <item msgid="4221763391123233270">"Подключено"</item>
+    <item msgid="624838831631122137">"Приостановлено"</item>
+    <item msgid="7979680559596111948">"Отключение..."</item>
+    <item msgid="1634960474403853625">"Нет подключения"</item>
+    <item msgid="746097431216080650">"Сбой"</item>
+    <item msgid="6367044185730295334">"Заблокировано"</item>
+    <item msgid="503942654197908005">"Временно избегать плохого соединения"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"Получение IP-адреса от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Подключено к <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Приостановлено"</item>
+    <item msgid="7698638434317271902">"Отключение от <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Нет подключения"</item>
+    <item msgid="8578370891960825148">"Сбой"</item>
+    <item msgid="5660739516542454527">"Заблокировано"</item>
+    <item msgid="1805837518286731242">"Временно избегать плохого соединения"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
new file mode 100644
index 0000000..e2a4fc7
--- /dev/null
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Не удалось начать поиск сетей."</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Недоступна"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Подключение к Интернету отсутствует и не будет восстановлено автоматически."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Кто сохранил: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Установлено подключение через Ассистента Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Подключено к %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Доступно через %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Подключено, без Интернета"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Отключено"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Отключение..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Подключение..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Подключено"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Сопряжение..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Подключено (кроме HSP/HFP)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Подключено (кроме A2DP)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Подключено (нет доступа к сообщениям)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Подключено (кроме HSP/HFP/A2DP)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Профиль A2DP"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Профиль HSP/HFP"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Профиль OPP"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Профиль HID"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Интернет-доступ"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Обмен контактами"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Использовать для обмена контактами"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Профиль PAN"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Доступ к сообщениям"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ к SIM-карте"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Подключено к мультимедийному аудиоустройству"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Подключено к аудиоустройству телефона"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Установлено подключение к серверу передачи файлов"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Доступ к сообщениям"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Подключено к точке доступа"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Нет подключения к серверу передачи файлов"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Подключено к устройству ввода"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Используется интернет-подключение другого устройства"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Устройство работает в режиме модема"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Использовать для доступа к Интернету"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Использовать для доступа к сообщениям"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Использовать для доступа к SIM-карте"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Использовать для мультимедийного аудиоустройства"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Использовать для аудиоустройства телефона"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Используется для передачи файлов"</string>
+    <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_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-код или пароль."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Не удается установить соединение с устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\"."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> не разрешает сопряжение."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi выключен"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi отключен"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: одно деление"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: два деления"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: три деления"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi: надежный сигнал"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"ОС Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Удаленные приложения"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Удаленные приложения и пользователи"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB-модем"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Точка доступа Wi-Fi"</string>
+    <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="8101244883654409696">"Рабочий профиль"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Гость"</string>
+    <string name="unknown" msgid="1592123443519355854">"Неизвестно"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Пользователь: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/arrays.xml b/packages/SettingsLib/res/values-si-rLK/arrays.xml
new file mode 100644
index 0000000..225ea36
--- /dev/null
+++ b/packages/SettingsLib/res/values-si-rLK/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"සම්බන්ධ වෙමින්…"</item>
+    <item msgid="515055375277271756">"සත්‍යාපනය වෙමින්…"</item>
+    <item msgid="1943354004029184381">"IP ලිපිනය ලබාගනිමින්…"</item>
+    <item msgid="4221763391123233270">"සම්බන්ධිතයි"</item>
+    <item msgid="624838831631122137">"අත්හිටුවන ලදි"</item>
+    <item msgid="7979680559596111948">"විසන්ධි වෙමින්…"</item>
+    <item msgid="1634960474403853625">"විසන්ධි වුණි"</item>
+    <item msgid="746097431216080650">"අසාර්ථකයි"</item>
+    <item msgid="6367044185730295334">"අවහිර කරන ලදි"</item>
+    <item msgid="503942654197908005">"දුර්වල සම්බන්ධතාවය තාවකාලිකව මඟහරිමින්"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> වෙත සම්බන්ධ වුණි"</item>
+    <item msgid="1330262655415760617">"අත්හිටුවන ලදි"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> වෙතින් විසන්ධි වෙමින්…"</item>
+    <item msgid="197508606402264311">"විසන්ධි විය"</item>
+    <item msgid="8578370891960825148">"අසාර්ථකයි"</item>
+    <item msgid="5660739516542454527">"අවහිර කරන ලදි"</item>
+    <item msgid="1805837518286731242">"දුර්වල සම්බන්ධතාවය තාවකාලිකව මඟහරිමින්"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
new file mode 100644
index 0000000..75302a0
--- /dev/null
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ජාල සඳහා පරිලෝකනය කළ නොහැක"</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_network_failure" msgid="2364951338436007124">"IP වින්‍යාස කිරීම අසාර්ථකයි"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi සම්බන්ධතාව අසාර්ථකයි"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"සත්‍යාපනයේ ගැටලුවකි"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"පරාසයේ නැත"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"අන්තර්ජාල ප්‍රවේශය අනාවරණය වුයේ නැත, ස්වයංක්‍රිය නැවත සම්බන්ධ වීම වූ නැත"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> විසින් සුරකින ලදී"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi සහායක හරහා සම්බන්ධ කරන ලදි"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s හරහා සම්බන්ධ විය"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"විසන්ධි වුණි"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"විසන්ධි වෙමින්…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"සම්බන්ධ වෙමින්…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"සම්බන්ධිතයි"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"යුගල කරමින්…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"සම්බන්ධයි (දුරකථන නැත)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"සම්බන්ධිතයි (මාධ්‍යයක් නොමැත)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"සම්බන්ධිතයි (පණිවිඩ ප්‍රවේශ නොමැත)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"සම්බන්ධිතයි (දුරකතනයක් හෝ මාධ්‍යයක් නැත)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"මාධ්‍ය ශ්‍රව්‍ය"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"දුරකථන ශ්‍රව්‍ය"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ගොනු හුවමාරුව"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ආදාන උපාංගය"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"අන්තර්ජාල ප්‍රවේශය"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"සම්බන්ධතා බෙදාගැනීම"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"සම්බන්ධතා බෙදාගැනීම සඳහා භාවිතා කිරීම"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"අන්තර්ජාල සම්බන්ධතා බෙදාගැනීම"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"පණිවිඩ ප්‍රවේශය"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ප්‍රවේශය"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"මාධ්‍ය ශ්‍රව්‍යට සම්බන්ධ විය"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"දුරකතනයේ ශ්‍රව්‍යට සම්බන්ධ විය"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ගොනු හුවමාරු සේවාදායකය සමග සම්බන්ධ විය"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"සිතියම වෙත සම්බන්ධිතයි"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP වෙත සම්බන්ධ විය"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ගොනු හුවමාරු සේවාදායකය වෙත සම්බන්ධ වී නොමැත"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ආදාන උපාංග වෙත සම්බන්ධිතයි"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"අන්තර්ජාල ප්‍රවේශය සඳහා උපාංගය වෙත සම්බන්ධ වුණි"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"මෙම උපාංගය සමඟ පෙදෙසි අන්තර්ජාල සම්බන්ධතාවය බෙදාගනිමින්"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"අන්තර්ජාල ප්‍රවේශය සඳහා භාවිතා කරන්න"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"සිතියම සඳහා භාවිතා කරන්න"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ප්‍රවේශය සඳහා භාවිත කරන්න"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"මාධ්‍ය ශ්‍රව්‍ය සඳහා භාවිතා කරන්න"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"දුරකථන ශ්‍රව්‍ය සඳහා භාවිතා කෙරේ"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ගොනු හුවමාරුව සඳහා භාවිතා කරන්න"</string>
+    <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_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">"වැරදි PIN එකක් හෝ පාස් යතුරක් නිසා <xliff:g id="DEVICE_NAME">%1$s</xliff:g> සමඟ යුගල කිරීමට නොහැකිය."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> සමඟ සන්නිවේදනය කළ නොහැක."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> විසින් යුගල කිරීම ප්‍රතික්ෂේප කරන ලදි."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi අක්‍රියයි."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi සම්බන්ධ කර නොමැත."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi තීරු එකයි."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi තීරු දෙකයි."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WiFi තීරු තුනයි."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi සංඥාව පිරී ඇත."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ඉවත් කළ යෙදුම්"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"යෙදුම් සහ පරිශීලකයින් ඉවත් කරන ලදි"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ටෙදරින්"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ජංගම හොට්ස්පොට්"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"බ්ලූටූත් ටෙදරින්"</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="8101244883654409696">"කාර්යාල පැතිකඩ"</string>
+    <string name="user_guest" msgid="8475274842845401871">"අමුත්තා"</string>
+    <string name="unknown" msgid="1592123443519355854">"නොදනී"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"පරිශීලකයා: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
new file mode 100644
index 0000000..6cab133
--- /dev/null
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Prebieha vyhľadávanie..."</item>
+    <item msgid="8513729475867537913">"Prebieha pripájanie…"</item>
+    <item msgid="515055375277271756">"Prebieha overovanie…"</item>
+    <item msgid="1943354004029184381">"Získava sa adresa IP…"</item>
+    <item msgid="4221763391123233270">"Pripojené"</item>
+    <item msgid="624838831631122137">"Pozastavená"</item>
+    <item msgid="7979680559596111948">"Prebieha odpájanie..."</item>
+    <item msgid="1634960474403853625">"Odpojený"</item>
+    <item msgid="746097431216080650">"Neúspešné"</item>
+    <item msgid="6367044185730295334">"Blokované"</item>
+    <item msgid="503942654197908005">"Dočasne bolo zabránené slabému pripojeniu"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Prebieha vyhľadávanie..."</item>
+    <item msgid="355508996603873860">"Prebieha pripájanie k sieti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Prebieha overovanie v sieti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Získava sa adresa IP zo siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Pripojené k sieti <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Pozastavená"</item>
+    <item msgid="7698638434317271902">"Prebieha odpájanie od siete <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="197508606402264311">"Odpojený"</item>
+    <item msgid="8578370891960825148">"Neúspešné"</item>
+    <item msgid="5660739516542454527">"Blokované"</item>
+    <item msgid="1805837518286731242">"Dočasne bolo zabránené slabému pripojeniu"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
new file mode 100644
index 0000000..d83c4bd
--- /dev/null
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Siete sa nedajú vyhľadávať"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Žiadne"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Uložené"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Zakázané"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Zlyhanie konfigurácie adresy IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Zlyhanie pripojenia Wi-Fi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problém s overením totožnosti"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nenašiel sa žiadny prístup k internetu, preto nedôjde k automatickému opätovnému pripojeniu"</string>
+    <string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Pripojené pomocou Asistenta Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"K dispozícii prostredníctvom %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Pripojené, žiadny internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Odpojený"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prebieha odpájanie..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Prebieha pripájanie…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Pripojené"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Párovanie..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Pripojené (bez telefónu)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Pripojené (bez média)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Pripojené (bez prístupu ku správam)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Pripojené (bez telefónu alebo média)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvuk medií"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvuk telefónu"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos súborov"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Vstupné zariadenie"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Prístup na Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Zdieľanie kontaktov"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Použiť na zdieľanie kontaktov"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Zdieľanie pripojenia na Internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Prístup ku správam"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Prístup k SIM karte"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Pripojené ku zvukovému médiu"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Pripojené ku zvuku telefónu"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Pripojené na server pre prenos údajov"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Pripojené k mape"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Pripojené k systému SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nepripojené k serveru pre prenos súborov"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Pripojené na vstupné zariadenie"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Pripoj. k zariad. s príst. na Internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Zdieľa miestne internet. pripoj. so zariad"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Použiť na prístup k Internetu"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Použiť pre mapu"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Použiť na pristupovanie k SIM karte"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Umožňuje pripojenie zvukového média"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Použiť pre zvuk telefónu"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Použiť na prenos súborov"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Použiť pre vstup"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Párovať"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"PÁROVAŤ"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Zrušiť"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Párovaním udelíte zariadeniam po pripojení prístup k svojim kontaktom a histórii hovorov."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nepodarilo sa spárovať so zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nepodarilo sa spárovať so zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>, pretože ste zadali nesprávny kód PIN alebo prístupový kľúč."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"So zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g> nie je možné komunikovať."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Párovanie odmietnuté zariadením <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Sieť Wi-Fi je vypnutá."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Sieť Wi-Fi je odpojená."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Jedna čiarka signálu Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dve čiarky signálu Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tri čiarky signálu Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Plný signál Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odstránené aplikácie"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odstránené aplikácie a používatelia"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Zdieľané pripojenie cez USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosný prístupový bod"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Pripojenie cez Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Zdieľanie dát. pripojenia"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Zdieľané pripojenie a prenosný hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Pracovný profil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Hosť"</string>
+    <string name="unknown" msgid="1592123443519355854">"Neznáme"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Používateľ: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Predvolená pre niektoré akcie"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nie je predvolená pre žiadne akcie"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-sl/arrays.xml b/packages/SettingsLib/res/values-sl/arrays.xml
new file mode 100644
index 0000000..fef1fdd
--- /dev/null
+++ b/packages/SettingsLib/res/values-sl/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Iskanje …"</item>
+    <item msgid="8513729475867537913">"Vzpostavljanje povezave ..."</item>
+    <item msgid="515055375277271756">"Preverjanje pristnosti ..."</item>
+    <item msgid="1943354004029184381">"Pridobivanje naslova IP …"</item>
+    <item msgid="4221763391123233270">"Povezava je vzpostavljena"</item>
+    <item msgid="624838831631122137">"Odloženo"</item>
+    <item msgid="7979680559596111948">"Prekinjanje povezave ..."</item>
+    <item msgid="1634960474403853625">"Prekinjena povezava"</item>
+    <item msgid="746097431216080650">"Ni uspelo"</item>
+    <item msgid="6367044185730295334">"Blokirano"</item>
+    <item msgid="503942654197908005">"Začasno izogibanje slabi povezavi"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Iskanje …"</item>
+    <item msgid="355508996603873860">"Vzpostavljanje povezave z omrežjem <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="554971459996405634">"Preverjanje pristnosti v omrežju <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="7928343808033020343">"Pridobivanje naslova IP od <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="8937994881315223448">"Povezava z omrežjem <xliff:g id="NETWORK_NAME">%1$s</xliff:g> je vzpostavljena"</item>
+    <item msgid="1330262655415760617">"Začasno ustavljeno"</item>
+    <item msgid="7698638434317271902">"Prekinjanje povezave z omrežjem <xliff:g id="NETWORK_NAME">%1$s</xliff:g> …"</item>
+    <item msgid="197508606402264311">"Prekinjena povezava"</item>
+    <item msgid="8578370891960825148">"Ni uspelo"</item>
+    <item msgid="5660739516542454527">"Blokirano"</item>
+    <item msgid="1805837518286731242">"Začasno izogibanje slabi povezavi"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
new file mode 100644
index 0000000..5b8b171
--- /dev/null
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ni mogoče iskati omrežij"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Brez"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Shranjeno"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Onemogočeno"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Konfiguracija IP-ja ni uspela"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Povezava prek Wi-Fi-ja ni uspela"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Težava s preverjanjem pristnosti"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ni v obsegu"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ni zaznanega dostopa do interneta; samodejna vnovična vzpostavitev povezave se ne bo izvedla."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Shranil(-a): <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Povezava vzpostavljena prek pomočnika za Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Vzpostavljena povezava prek: %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Na voljo prek: %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Vzpostavljena povezava, brez interneta"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Prekinjena povezava"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Prekinjanje povezave ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Vzpostavljanje povezave ..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Povezava je vzpostavljena"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Seznanjanje ..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Povezava vzpostavljena (brez telefona)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Povezava vzpostavljena (brez predstavnosti)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Povezava vzp. (ni dostopa do sporočil)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Povezava vzpostavljena (brez telefona ali predstavnosti)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Zvok predstavnosti"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Zvok telefona"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Prenos datoteke"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Vnosna naprava"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetni dostop"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Dajanje stikov v skupno rabo"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Uporabi za dajanje stikov v skupno rabo"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Skupna raba internetne povezave"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Dostop do sporočil"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Dostop do kartice SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Povezan s profilom za predstavnostni zvok"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Povezava s profilom za zvok telefona vzpostavljena"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Povezava s strežnikom za prenos datotek je vzpostavljena"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Povezava je vzpostavljena z zemljevidom"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Vzpostavljena povezava s profilom SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Povezava s strežnikom za prenos datotek ni vzpostavljena"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Povezava z vnosno napravo je vzpostavljena"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Povezava z napravo za internetni dostop"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Skupna raba lok. internetne povezave z napravo"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Uporabi za dostop do interneta"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Uporabi za zemljevid"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Uporablja se za dostop do kartice SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Uporabi za zvok predstavnosti"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Uporabi za zvok telefona"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Uporabi za prenos datotek"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Uporabi za vnos"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Seznani"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"SEZNANI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Prekliči"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Seznanjanje pri vzpostavljeni povezavi omogoči dostop do vaših stikov in zgodovine klicev."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Ni bilo mogoče vzpostaviti povezave z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Zaradi nepravilne kode PIN ali gesla ni mogoče vzpostaviti povezave z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Z napravo <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ni mogoče vzpostaviti povezave."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Naprava <xliff:g id="DEVICE_NAME">%1$s</xliff:g> je zavrnila seznanitev."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi je izklopljen."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Povezava Wi-Fi je prekinjena."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Ena črtica signala Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Dve črtici signala Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tri črtice signala Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Poln signal Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odstranjene aplikacije"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odstranjene aplikacije in uporabniki"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Internet prek USB-ja"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosna dostopna točka"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Internet prek Bluetootha"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Internet prek mob. napr."</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Modem/prenosna dost. točka"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Delovni profil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gost"</string>
+    <string name="unknown" msgid="1592123443519355854">"Neznano"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Uporabnik: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Nastavljene so nekatere privzete nastavitve"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Ni privzetih nastavitev"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/arrays.xml b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
new file mode 100644
index 0000000..5aceb09
--- /dev/null
+++ b/packages/SettingsLib/res/values-sq-rAL/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Po skanon..."</item>
+    <item msgid="8513729475867537913">"Po lidhet..."</item>
+    <item msgid="515055375277271756">"Po vërteton…"</item>
+    <item msgid="1943354004029184381">"Po merr adresën IP…"</item>
+    <item msgid="4221763391123233270">"I lidhur"</item>
+    <item msgid="624838831631122137">"I pezulluar"</item>
+    <item msgid="7979680559596111948">"Po shkëputet..."</item>
+    <item msgid="1634960474403853625">"I shkëputur"</item>
+    <item msgid="746097431216080650">"I pasuksesshëm"</item>
+    <item msgid="6367044185730295334">"I bllokuar"</item>
+    <item msgid="503942654197908005">"Po shmang përkohësisht lidhje të dobët"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Po skanon..."</item>
+    <item msgid="355508996603873860">"Po lidhet me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Po kryen vërtetimin me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Po merr adresën IP nga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"I lidhur me <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"I pezulluar"</item>
+    <item msgid="7698638434317271902">"I shkëputur nga <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="197508606402264311">"I shkëputur"</item>
+    <item msgid="8578370891960825148">"I pasuksesshëm"</item>
+    <item msgid="5660739516542454527">"I bllokuar"</item>
+    <item msgid="1805837518286731242">"Përkohësisht duke shmangur një lidhje të dobët"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
new file mode 100644
index 0000000..d81d8c7
--- /dev/null
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Nuk mund të skanojë për rrjete"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Asnjë"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"U ruajt"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Të çaktivizuara"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Dështim në konfigurimin e IP-së"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Dështim i lidhjes WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problem me vërtetimin"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Nuk është brenda rrezes"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Nuk u diktua qasje në internet. Lidhja nuk do të realizohet automatikisht."</string>
+    <string name="saved_network" msgid="4352716707126620811">"E ruajtur nga <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"I lidhur nëpërmjet ndihmësit të Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"E lidhur përmes %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"E mundshme përmes %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"U lidh, nuk ka internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Shkëputur"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Po shkëputet..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Po lidhet..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"U lidh"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Po çiftohet..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"U lidh (pa telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"U lidh (nuk ka media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"U lidh (pa qasje te mesazhet)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"I lidhur (pa telefon apo media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audioja e klipit \"media\""</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audioja e telefonit"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Transferimi i skedarëve"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Pajisja e hyrjes"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Qasja në internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Ndarja e kontakteve"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Përdore për ndarjen e kontakteve"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Ndarja e lidhjes së internetit"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Qasja në mesazhe"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Qasje në kartën SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"U lidh me audion e medias"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"U lidh me audion e telefonit"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"U lidh me serverin e transferimit të skedarëve"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"U lidh me hartën"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Lidhur me SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Nuk u lidh me serverin e transferimit të skedarëve"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"U lidh me pajisjen e hyrjes"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Lidhur me pajisjen për qasje në internet"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Po ndan lidhjen lokale të internetit me pajisjen"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Përdor për qasje në internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Përdore për hartën"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Përdor për qasje në kartën SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Përdor për audion e medias"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Përdor për audion e telefonit"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Përdor për transferimin e skedarëve"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Përdore për hyrjen"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Çifto"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ÇIFTO"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Anulo"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Çiftimi lejon qasjen te kontaktet dhe historiku yt i telefonatave."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Nuk mundi të çiftohej me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Nuk mundi të çiftohej me <xliff:g id="DEVICE_NAME">%1$s</xliff:g> për shkak të një kodi PIN ose një kodi të pasaktë."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Nuk mund të komunikohet me <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Çiftimi u refuzua nga <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi është çaktivizuar."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi është i shkëputur."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi ka një vijë."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi ka dy vija."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: tre vija."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi ka sinjal të plotë."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Sistemi operativ Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Aplikacionet e hequra"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Aplikacionet dhe përdoruesit e hequr"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Ndarje përmes USB-së"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Zona e qasjes e lëvizshme"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Ndarje interneti përmes Bluetooth-it"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Ndarja e internetit"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Zonë qasjeje dhe ndarjeje interneti"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profili i punës"</string>
+    <string name="user_guest" msgid="8475274842845401871">"I ftuar"</string>
+    <string name="unknown" msgid="1592123443519355854">"I panjohur"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Përdoruesi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Disa caktime me parazgjedhje"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Nuk janë caktuar parazgjedhje"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-sr/arrays.xml b/packages/SettingsLib/res/values-sr/arrays.xml
new file mode 100644
index 0000000..cc60251
--- /dev/null
+++ b/packages/SettingsLib/res/values-sr/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Повезивање…"</item>
+    <item msgid="515055375277271756">"Потврђује се аутентичност..."</item>
+    <item msgid="1943354004029184381">"Преузимање IP адресе..."</item>
+    <item msgid="4221763391123233270">"Повезано"</item>
+    <item msgid="624838831631122137">"Обустављено"</item>
+    <item msgid="7979680559596111948">"Прекидање везе..."</item>
+    <item msgid="1634960474403853625">"Веза је прекинута"</item>
+    <item msgid="746097431216080650">"Неуспешно"</item>
+    <item msgid="6367044185730295334">"Блокирано"</item>
+    <item msgid="503942654197908005">"Привремено избегавање лоше везе"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"Добијање IP адресе од мреже <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Повезано са мрежом <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Обустављено"</item>
+    <item msgid="7698638434317271902">"Прекидање везе са мрежом <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Веза је прекинута"</item>
+    <item msgid="8578370891960825148">"Неуспешно"</item>
+    <item msgid="5660739516542454527">"Блокирано"</item>
+    <item msgid="1805837518286731242">"Привремено избегавање лоше везе"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
new file mode 100644
index 0000000..01a1993
--- /dev/null
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Није могуће скенирати мреже"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Није у опсегу"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Приступ интернету није откривен, аутоматско повезивање није могуће."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Сачувао/ла је <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Повезано преко Wi‑Fi помоћника"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Веза је успостављена преко приступне тачке %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Доступна је преко приступне тачке %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Веза је успостављена, нема интернета"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Веза је прекинута"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Прекидање везе..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Повезивање…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Повезано"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Упаривање..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Повезано (без телефона)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Повезано (без медија)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Повезано је (нема приступа порукама)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Повезано (без телефона или медија)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Звук медија"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Звук телефона"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Пренос датотеке"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Улазни уређај"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Приступ Интернету"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Дељење контаката"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Користите за дељење контаката"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Дељење интернет везе"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Приступ порукама"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Приступ SIM картици"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Повезано са звуком медија"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Повезано са звуком телефона"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Повезано са сервером за пренос датотека"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Повезано је са мапом"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Веза са тачком приступа услугама је успостављена"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Није повезано са сервером за пренос датотека"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Повезан са улазним уређајем"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Повез. са уређ. ради приступа Интернету"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Локална интернет веза се дели са уређајем"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Користи за приступ Интернету"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Користи се за мапу"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Користи за приступ SIM картици"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Коришћење за звук медија"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Коришћење за аудио телефона"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Коришћење за пренос датотека"</string>
+    <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_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-а или приступног кода."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Није могуће комуницирати са уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> је одбио/ла упаривање"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi је искључен."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi веза је прекинута."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi сигнал има једну црту."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi сигнал има две црте."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi сигнал има три црте."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi сигнал је најјачи."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android ОС"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Уклоњене апликације"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Уклоњене апликације и корисници"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB Интернет повезивање"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Преносни хотспот"</string>
+    <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="8101244883654409696">"Профил за посао"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Гост"</string>
+    <string name="unknown" msgid="1592123443519355854">"Непознато"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Корисник: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-sv/arrays.xml b/packages/SettingsLib/res/values-sv/arrays.xml
new file mode 100644
index 0000000..02b352c
--- /dev/null
+++ b/packages/SettingsLib/res/values-sv/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Skannar…"</item>
+    <item msgid="8513729475867537913">"Ansluter…"</item>
+    <item msgid="515055375277271756">"Autentiserar…"</item>
+    <item msgid="1943354004029184381">"Erhåller IP-adress…"</item>
+    <item msgid="4221763391123233270">"Ansluten"</item>
+    <item msgid="624838831631122137">"Pausad"</item>
+    <item msgid="7979680559596111948">"Kopplar ifrån…"</item>
+    <item msgid="1634960474403853625">"Frånkopplad"</item>
+    <item msgid="746097431216080650">"Misslyckades"</item>
+    <item msgid="6367044185730295334">"Blockerat"</item>
+    <item msgid="503942654197908005">"Undviker just nu dålig anslutning"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Skannar…"</item>
+    <item msgid="355508996603873860">"Ansluter till <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Autentiserar med <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Hämtar IP-adress från <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Ansluten till: <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Pausad"</item>
+    <item msgid="7698638434317271902">"Kopplar ifrån <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Frånkopplad"</item>
+    <item msgid="8578370891960825148">"Misslyckades"</item>
+    <item msgid="5660739516542454527">"Blockerat"</item>
+    <item msgid="1805837518286731242">"Undviker just nu dålig anslutning"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
new file mode 100644
index 0000000..18b09f4
--- /dev/null
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Det går inte att söka efter nätverk"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Ingen"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Sparat"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Inaktiverad"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP-konfigurationsfel"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi-anslutningsfel"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Autentiseringsproblem"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Utom räckhåll"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ingen internetåtkomst hittades. Det går inte att återansluta automatiskt."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Sparades av <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Ansluten via Wi-Fi-assistent"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Anslutet via %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Tillgängligt via %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ansluten, inget internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Kopplas ifrån"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Kopplar ifrån…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Ansluter…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Ansluten"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Parkoppling…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ansluten (ingen telefon)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ansluten (inga media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ansluten (ingen meddelandeåtkomst)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ansluten (ingen telefon och inga media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medialjud"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefonljud"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Filöverföring"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Indataenhet"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetåtkomst"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktdelning"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Använd för kontaktdelning"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Delning av Internetanslutning"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Meddelandeåtkomst"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-åtkomst"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ansluten till medialjud"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ansluten till telefonens ljud"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ansluten till filöverföringsserver"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Ansluten till MAP"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ansluten till SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Inte ansluten till filöverföringsserver"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ansluten till indataenhet"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ansluten för Internetåtkomst"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Dela lokal Internetanslutning med enhet"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Använd för Internetåtkomst"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Använd för MAP"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Använd för SIM-åtkomst"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Använd för medialjud"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Använd för telefonens ljud"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Använd för filöverföring"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Använd för inmatning"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Parkoppling"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"KOPPLA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Avbryt"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Om du kopplar enheten får du tillgång till dina kontakter och din samtalshistorik när du är ansluten."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Det gick inte att koppla till <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Det gick inte att koppla till <xliff:g id="DEVICE_NAME">%1$s</xliff:g> på grund av en felaktig PIN-kod eller nyckel."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Det går inte att kommunicera med <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Parkoppling avvisad av <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi är inaktiverat."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Ingen Wi-Fi-anslutning."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: en stapel."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: två staplar."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: tre staplar."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Full signalstyrka för Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Operativsystemet Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Borttagna appar"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Borttagna appar och användare"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Internetdelning via USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Mobil surfpunkt"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Delning via Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Internetdelning"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Internetdelning och surfpunkt"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Arbetsprofil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Gäst"</string>
+    <string name="unknown" msgid="1592123443519355854">"Okänd"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Användare: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Några standardinställningar har angetts"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Inga standardinställningar har angetts"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-sw/arrays.xml b/packages/SettingsLib/res/values-sw/arrays.xml
new file mode 100644
index 0000000..cbd906d
--- /dev/null
+++ b/packages/SettingsLib/res/values-sw/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Inasafisha..."</item>
+    <item msgid="8513729475867537913">"Inaunganisha…"</item>
+    <item msgid="515055375277271756">"Inathibitisha..."</item>
+    <item msgid="1943354004029184381">"Inapata anwani ya Ip..."</item>
+    <item msgid="4221763391123233270">"Umeunganishwa"</item>
+    <item msgid="624838831631122137">"Imesimamishwa"</item>
+    <item msgid="7979680559596111948">"Inakatisha muunganisho..."</item>
+    <item msgid="1634960474403853625">"Muunganisho Umekatika"</item>
+    <item msgid="746097431216080650">"Haijafanikiwa"</item>
+    <item msgid="6367044185730295334">"Imezuiwa"</item>
+    <item msgid="503942654197908005">"Inaepuka kwa muda muunganisho mbovu"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Inasafisha..."</item>
+    <item msgid="355508996603873860">"Inaunganisha kwa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Uhalalishaji kwa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Inamiliki anwani ya IP kutoka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">" Umeunganishwa kwa<xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Imesimamishwa"</item>
+    <item msgid="7698638434317271902">"inakatisha muunganisho kutoka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Muunganisho Umekatika"</item>
+    <item msgid="8578370891960825148">"Haijafanikiwa"</item>
+    <item msgid="5660739516542454527">"Imezuiwa"</item>
+    <item msgid="1805837518286731242">"Inaepuka kwa muda muunganisho mbovu"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
new file mode 100644
index 0000000..8b77301
--- /dev/null
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Haiwezi kutambaza mitandao"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Hamna"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Imehifadhiwa"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Imelemazwa"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Haikuweza Kusanidi IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Haikuweza Kuunganisha kwenye WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tatizo la uthibitishaji"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Haiko karibu"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Hakuna Ufikiaji kwa Intaneti Uliogunduliwa, haitaweza kuunganisha kiotomatiki."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Ilihifadhiwa na <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Imeunganishwa kupitia Kisaidizi cha Wi-Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Imeunganishwa kupitia %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Inapatikana kupitia %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Imeunganishwa, hakuna Intaneti"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Imetenganishwa"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Inatenganisha..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Inaunganisha…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Umeunganishwa"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Inaoanisha..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Imeunganishwa (hakuna simu)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Imeunganishwa(hakuna vyombo vya habari)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Imeunganishwa (hakuna ufikiaji kwa ujumbe)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Imeunganishwa(hakuna simu au vyombo vya habari)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media ya sauti"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Sauti ya simu"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Uhamishaji wa faili"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Kifaa cha kuingiza"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Ufikivu wa mtandao"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kushiriki anwani"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Tumia kwa kushiriki anwani"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Kushiriki muunganisho wa tovuti"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Ufikiaji wa Ujumbe"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Ufikiaji wa SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Imeunganishwa kwenye sikika ya njia ya mawasiliano"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Imeunganishwa kwenye sauti ya simu"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Imeunganishwa kwenye seva ya kuhamisha faili"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Imeunganishwa kwenye ramani"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Imeunganishwa kwenye SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Haijaunganishwa kwenye seva ya kuhamisha faili"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Umeunganishwa kwa kifaa cha kuingiza"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Umeunganishwa kwa kifaa cha ufikia Mtandao"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Kushiriki muunganisho wa mtandao wa nyumbani na kifaa"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Tumia kwa ufikiaji mtandao"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Tumia kwa ramani"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Tumia kwa ufikiaji wa SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Tumia kwa sauti ya media"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Tumia kwa sauti ya simu"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Tumia kwa hali faili"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Tumia kwa kuingiza"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Oanisha"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"OANISHA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Ghairi"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Kuoanisha hutoa ruhusa ya kufikiwa kwa unaowasiliana nao na rekodi ya simu zilizopigwa unapounganishwa."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Haikuwezakulinganisha na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Haikuweza kulingana na <xliff:g id="DEVICE_NAME">%1$s</xliff:g> kwa sababu ya PIN isiyo sahihi au msimbo ya kuingia."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Haiwezi kuanzisha mawasiliano na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ulinganishaji umekataliwa na <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi imezimwa."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi imeondolewa."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kipima mtandao kimoja cha Wifi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Vipima mtandao viwili vya Wifi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Vipima mtandao vitatu vya Wifi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Nguvu kamili ya mtandao wa Wifi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"OS ya Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Programu zilizoondolewa"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Watumiaji na programu ziilizoondolewa"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Shiriki intaneti kwa USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Intaneti ya kusambazwa"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Shiriki intaneti kwa Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Inazuia"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Kushiriki na kusambaza intaneti"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Wasifu wa kazi"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Aliyealikwa"</string>
+    <string name="unknown" msgid="1592123443519355854">"Haijulikani"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Mtumiaji: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguo-msingi zimewekwa"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Hakuna chaguo-misingi zilizowekwa"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/arrays.xml b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
new file mode 100644
index 0000000..c554fea
--- /dev/null
+++ b/packages/SettingsLib/res/values-ta-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"இணைக்கிறது..."</item>
+    <item msgid="515055375277271756">"அங்கீகரிக்கிறது..."</item>
+    <item msgid="1943354004029184381">"IP முகவரியைப் பெறுகிறது…"</item>
+    <item msgid="4221763391123233270">"இணைக்கப்பட்டது"</item>
+    <item msgid="624838831631122137">"இடைநீக்கப்பட்டது"</item>
+    <item msgid="7979680559596111948">"துண்டிக்கிறது..."</item>
+    <item msgid="1634960474403853625">"தொடர்பு துண்டிக்கப்பட்டது"</item>
+    <item msgid="746097431216080650">"தோல்வி"</item>
+    <item msgid="6367044185730295334">"தடுக்கப்பட்டது"</item>
+    <item msgid="503942654197908005">"வேகம் குறைந்த இணைப்பைத் தற்காலிகமாகத் தவிர்க்கிறது"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> உடன் இணைக்கப்பட்டது"</item>
+    <item msgid="1330262655415760617">"இடைநீக்கப்பட்டது"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> இலிருந்து தொடர்பு துண்டிக்கப்படுகிறது…"</item>
+    <item msgid="197508606402264311">"தொடர்பு துண்டிக்கப்பட்டது"</item>
+    <item msgid="8578370891960825148">"தோல்வி"</item>
+    <item msgid="5660739516542454527">"தடுக்கப்பட்டது"</item>
+    <item msgid="1805837518286731242">"வேகம் குறைந்த இணைப்பைத் தற்காலிகமாகத் தவிர்க்கிறது"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
new file mode 100644
index 0000000..b9bc93c
--- /dev/null
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"நெட்வொர்க்குகளுக்கு ஸ்கேன் செய்யப்படவில்லை"</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_network_failure" msgid="2364951338436007124">"IP உள்ளமைவில் தோல்வி"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"வைஃபை இணைப்பில் தோல்வி"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"அங்கீகரிப்புச் சிக்கல்"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"தொடர்பு எல்லையில் இல்லை"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"இணைய அணுகல் இல்லை, மீண்டும் தானாக இணையாது."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> சேமித்தது"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"வைஃபை அசிஸ்டண்ட் மூலம் இணைக்கப்பட்டது"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s வழியாக இணைக்கப்பட்டது"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s வழியாகக் கிடைக்கிறது"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"இணைக்கப்பட்டது, இணையம் இல்லை"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"தொடர்பு துண்டிக்கப்பட்டது"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"துண்டிக்கிறது..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"இணைக்கிறது..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"இணைக்கிறது..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"இணைக்கப்பட்டது (மொபைல் இல்லை)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"இணைக்கப்பட்டது (மீடியா இல்லை)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"இணைக்கப்பட்டது (செய்திக்கான அணுகல் இல்லை)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"இணைக்கப்பட்டது (மொபைல் அல்லது மீடியாவுடன் அல்ல)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"மீடியா ஆடியோ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"மொபைல் ஆடியோ"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"கோப்பு இடமாற்றம்"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"உள்ளீட்டுச் சாதனம்"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"இணைய அணுகல்"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"தொடர்புப் பகிர்தல்"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"தொடர்புப் பகிர்தலுக்குப் பயன்படுத்து"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"இணைய இணைப்பு பகிர்தல்"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"செய்திக்கான அணுகல்"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"சிம் அணுகல்"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"மீடியா ஆடியோவுடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"மொபைல் ஆடியோவுடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"கோப்பைப் பரிமாற்றும் சேவையகத்துடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"வரைபடத்துடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP உடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"கோப்பு இடமாற்றும் சேவையகத்துடன் இணைக்கப்படவில்லை"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"உள்ளீட்டுச் சாதனத்துடன் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"இணைய அணுகலுக்காகச் சாதனம் இணைக்கப்பட்டது"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"சாதனத்துடன் அக இணைய இணைப்பைப் பகிர்கிறது"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"இணைய அணுகலுக்காகப் பயன்படுத்து"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"வரைபடத்திற்குப் பயன்படுத்து"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"சிம் அணுகலுக்குப் பயன்படுத்தும்"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"மீடியாவின் ஆடியோவிற்குப் பயன்படுத்து"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"மொபைல் ஆடியோவைப் பயன்படுத்து"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"கோப்பு பரிமாற்றத்திற்காகப் பயன்படுத்து"</string>
+    <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_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> உடன் இணைக்க முடியவில்லை."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> உடன் இணைக்க முடியவில்லை."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> இணைப்பதை நிராகரித்தது."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"வைஃபை முடக்கப்பட்டது."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"வைஃபை துண்டிக்கப்பட்டது."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"வைஃபை சிக்னல்: ஒரு கோடு."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"வைஃபை சிக்னல்: இரண்டு கோடுகள்."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"வைஃபை சிக்னல்: மூன்று கோடுகள்."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"வைஃபை சிக்னல் முழுமையாக உள்ளது."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"அகற்றப்பட்ட பயன்பாடுகள்"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"அகற்றப்பட்ட பயன்பாடுகள் மற்றும் பயனர்கள்"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB டெதெரிங்"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"போர்ட்டபிள் ஹாட்ஸ்பாட்"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"புளூடூத் டெதெரிங்"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"டெதெரிங்"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"டெதெரிங் &amp; போர்டபிள் ஹாட்ஸ்பாட்"</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">"பயனர்: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/arrays.xml b/packages/SettingsLib/res/values-te-rIN/arrays.xml
new file mode 100644
index 0000000..e21a5f4
--- /dev/null
+++ b/packages/SettingsLib/res/values-te-rIN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"కనెక్ట్ చేస్తోంది..."</item>
+    <item msgid="515055375277271756">"ప్రామాణీకరిస్తోంది…"</item>
+    <item msgid="1943354004029184381">"IP చిరునామాను పొందుతోంది…"</item>
+    <item msgid="4221763391123233270">"కనెక్ట్ చేయబడింది"</item>
+    <item msgid="624838831631122137">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
+    <item msgid="7979680559596111948">"డిస్‌కనెక్ట్ చేస్తోంది..."</item>
+    <item msgid="1634960474403853625">"డిస్‌కనెక్ట్ చేయబడింది"</item>
+    <item msgid="746097431216080650">"విఫలమైంది"</item>
+    <item msgid="6367044185730295334">"బ్లాక్ చేయబడింది"</item>
+    <item msgid="503942654197908005">"బలహీన కనెక్షన్‌ను తాత్కాలికంగా నివారిస్తోంది"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది"</item>
+    <item msgid="1330262655415760617">"తాత్కాలికంగా రద్దు చేయబడింది"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> నుండి డిస్‌కనెక్ట్ చేస్తోంది…"</item>
+    <item msgid="197508606402264311">"డిస్‌కనెక్ట్ చేయబడింది"</item>
+    <item msgid="8578370891960825148">"విఫలమైంది"</item>
+    <item msgid="5660739516542454527">"బ్లాక్ చేయబడింది"</item>
+    <item msgid="1805837518286731242">"బలహీన కనెక్షన్‌ను తాత్కాలికంగా నివారిస్తోంది"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
new file mode 100644
index 0000000..6f66940
--- /dev/null
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"నెట్‌వర్క్‌ల కోసం స్కాన్ చేయడం సాధ్యపడదు"</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_network_failure" msgid="2364951338436007124">"IP కాన్ఫిగరేషన్ వైఫల్యం"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi కనెక్షన్ వైఫల్యం"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"ప్రామాణీకరణ సమస్య"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"పరిధిలో లేదు"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ఇంటర్నెట్ ప్రాప్యత కనుగొనబడలేదు, స్వయంచాలకంగా మళ్లీ కనెక్ట్ చేయబడదు."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా సేవ్ చేయబడింది"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi సహాయకం ద్వారా కనెక్ట్ చేయబడింది"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s ద్వారా కనెక్ట్ చేయబడింది"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"డిస్‌కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"డిస్‌కనెక్ట్ చేస్తోంది..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"కనెక్ట్ చేస్తోంది..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"జత చేస్తోంది..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"కనెక్ట్ చేయబడింది (ఫోన్‌ కాదు)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"కనెక్ట్ చేయబడింది (మీడియా కాదు)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"కనెక్ట్ చేయబడింది (సందేశ ప్రాప్యత లేదు)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"కనెక్ట్ చేయబడింది (ఫోన్ లేదా మీడియా కాకుండా)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"మీడియా ఆడియో"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"ఫోన్ ఆడియో"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"ఫైల్ బదిలీ"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ఇన్‌పుట్ పరికరం"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"ఇంటర్నెట్ ప్రాప్యత"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"పరిచయ భాగస్వామ్యం"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"పరిచయ భాగస్వామ్యం కోసం ఉపయోగించు"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"ఇంటర్నెట్ కనెక్షన్ భాగస్వామ్యం"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"సందేశ ప్రాప్యత"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM ప్రాప్యత"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"మీడియా ఆడియోకు కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"ఫోన్ ఆడియోకు కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"ఫైల్ బదిలీ సర్వర్‌కు కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"మ్యాప్‌కు కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAPకి కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ఫైల్ బదిలీ సర్వర్‌కు కనెక్ట్ చేయబడలేదు"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ఇన్‌పుట్ పరికరానికి కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"ఇంటర్నెట్ ప్రాప్యత కోసం పరికరానికి కనెక్ట్ చేయబడింది"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"స్థానిక ఇంటర్నెట్ కనెక్షన్‌ను పరికరంతో భాగస్వామ్యం చేయడం"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ఇంటర్నెట్ ప్రాప్యత కోసం ఉపయోగించు"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"మ్యాప్ కోసం ఉపయోగించు"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM ప్రాప్యత కోసం ఉపయోగించబడుతుంది"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"మీడియా ఆడియో కోసం ఉపయోగించు"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ఫోన్ ఆడియో కోసం ఉపయోగించు"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ఫైల్ బదిలీ కోసం ఉపయోగించు"</string>
+    <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_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>తో జత చేయడం సాధ్యపడలేదు."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> జత చేయడాన్ని తిరస్కరించింది."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi ఆఫ్‌లో ఉంది."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi డిస్‌కనెక్ట్ చేయబడింది."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi సిగ్నల్ ఒక బార్ ఉంది."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wifi సిగ్నల్ రెండు బార్‌లు ఉంది."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wifi సిగ్నల్ మూడు బార్‌లు ఉంది."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wifi సిగ్నల్ పూర్తిగా ఉంది."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"తీసివేయబడిన అనువర్తనాలు"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"తీసివేయబడిన అనువర్తనాలు మరియు వినియోగదారులు"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB టీథరింగ్"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"పోర్టబుల్ హాట్‌స్పాట్"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"బ్లూటూత్ టీథరింగ్"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"టీథరింగ్"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"టీథరింగ్ &amp; పోర్టబుల్ హాట్‌స్పాట్"</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">"వినియోగదారు: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-th/arrays.xml b/packages/SettingsLib/res/values-th/arrays.xml
new file mode 100644
index 0000000..190a37d
--- /dev/null
+++ b/packages/SettingsLib/res/values-th/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"กำลังเชื่อมต่อ…"</item>
+    <item msgid="515055375277271756">"กำลังตรวจสอบความถูกต้อง…"</item>
+    <item msgid="1943354004029184381">"กำลังรับที่อยู่ IP…"</item>
+    <item msgid="4221763391123233270">"เชื่อมต่อแล้ว"</item>
+    <item msgid="624838831631122137">"ระงับไว้"</item>
+    <item msgid="7979680559596111948">"กำลังตัดการเชื่อมต่อ..."</item>
+    <item msgid="1634960474403853625">"ตัดการเชื่อมต่อ"</item>
+    <item msgid="746097431216080650">"ไม่สำเร็จ"</item>
+    <item msgid="6367044185730295334">"ถูกบล็อก"</item>
+    <item msgid="503942654197908005">"หลีกเลี่ยงการเชื่อมต่อกับสัญญาณที่ไม่แรงพอชั่วคราว"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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">"กำลังรับที่อยู่ IP จาก <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"เชื่อมต่อกับ <xliff:g id="NETWORK_NAME">%1$s</xliff:g> แล้ว"</item>
+    <item msgid="1330262655415760617">"ระงับไว้"</item>
+    <item msgid="7698638434317271902">"กำลังตัดการเชื่อมต่อจาก <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="197508606402264311">"ตัดการเชื่อมต่อ"</item>
+    <item msgid="8578370891960825148">"ไม่สำเร็จ"</item>
+    <item msgid="5660739516542454527">"ถูกบล็อก"</item>
+    <item msgid="1805837518286731242">"หลีกเลี่ยงการเชื่อมต่อกับสัญญาณที่ไม่แรงพอชั่วคราว"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
new file mode 100644
index 0000000..c1febf2
--- /dev/null
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"ไม่สามารถสแกนหาเครือข่าย"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"ไม่อยู่ในพื้นที่ให้บริการ"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"ไม่พบการเข้าถึงอินเทอร์เน็ต ระบบจะไม่เชื่อมต่อใหม่โดยอัตโนมัติ"</string>
+    <string name="saved_network" msgid="4352716707126620811">"บันทึกโดย <xliff:g id="NAME">%1$s</xliff:g> แล้ว"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"เชื่อมต่อผ่านตัวช่วย Wi-Fi อยู่"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"เชื่อมต่อผ่าน %1$s แล้ว"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"พร้อมใช้งานผ่านทาง %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"ตัดการเชื่อมต่อ"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"กำลังตัดการเชื่อมต่อ..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"กำลังเชื่อมต่อ…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"เชื่อมต่อแล้ว"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"กำลังกำหนดค่าอุปกรณ์ให้ตรงกัน..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"เชื่อมต่อแล้ว (ยกเว้นเสียงโทรศัพท์)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"เชื่อมต่อแล้ว (ยกเว้นเสียงสื่อ)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"เชื่อมต่อแล้ว (ไม่มีการเข้าถึงข้อความ)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"เชื่อมต่อ (ยกเว้นเสียงโทรศัพท์หรือสื่อ)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"เสียงสื่อ"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"เสียงโทรศัพท์"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"การถ่ายโอนไฟล์"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"อุปกรณ์อินพุต"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"การเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"การแชร์รายชื่อผู้ติดต่อ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"ใช้สำหรับการแชร์รายชื่อผู้ติดต่อ"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"การแชร์การเชื่อมต่ออินเทอร์เน็ต"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"การเข้าถึงข้อความ"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"การเข้าถึงซิม"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"เชื่อมต่อกับระบบเสียงของสื่อแล้ว"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"เชื่อมต่อกับระบบเสียงของโทรศัพท์แล้ว"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"เชื่อมต่อกับเซิร์ฟเวอร์สำหรับโอนไฟล์แล้ว"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"เชื่อมต่อกับแผนที่แล้ว"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"เชื่อมต่อ SAP แล้ว"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"ไม่ได้เชื่อมต่อกับเซิร์ฟเวอร์สำหรับโอนไฟล์"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"เชื่อมต่อกับอุปกรณ์อินพุตแล้ว"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"เชื่อมต่อกับอุปกรณ์สำหรับการเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"กำลังแชร์อินเทอร์เน็ตกับอุปกรณ์"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"ใช้การเข้าถึงอินเทอร์เน็ต"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"ใช้สำหรับแผนที่"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"ใช้สำหรับการเข้าถึงซิม"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"ใช้สำหรับระบบเสียงของสื่อ"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"ใช้สำหรับระบบเสียงของโทรศัพท์"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"ใช้สำหรับการโอนไฟล์"</string>
+    <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_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 หรือรหัสผ่านไม่ถูกต้อง"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"ไม่สามารถเชื่อมต่อกับ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"การกำหนดค่าอุปกรณ์ให้ตรงกันถูกปฏิเสธโดย <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi ปิดอยู่"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"ไม่ได้เชื่อมต่อ Wi-Fi"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"สัญญาณ Wi-Fi 1 ขีด"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"สัญญาณ Wi-Fi 2 ขีด"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"สัญญาณ Wi-Fi 3 ขีด"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"สัญญาณ Wi-Fi เต็ม"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"ระบบปฏิบัติการของ Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"แอปพลิเคชันที่นำออก"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"แอปพลิเคชันและผู้ใช้ที่นำออก"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"ปล่อยสัญญาณผ่าน USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ฮอตสปอตแบบพกพาได้"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ปล่อยสัญญาณบลูทูธ"</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="8101244883654409696">"โปรไฟล์งาน"</string>
+    <string name="user_guest" msgid="8475274842845401871">"ผู้เข้าร่วม"</string>
+    <string name="unknown" msgid="1592123443519355854">"ไม่ทราบ"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"ผู้ใช้: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-tl/arrays.xml b/packages/SettingsLib/res/values-tl/arrays.xml
new file mode 100644
index 0000000..35c9724
--- /dev/null
+++ b/packages/SettingsLib/res/values-tl/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Nag-i-scan…"</item>
+    <item msgid="8513729475867537913">"Kumukonekta…"</item>
+    <item msgid="515055375277271756">"Pinapatunayan…"</item>
+    <item msgid="1943354004029184381">"Kumukuha ng IP address…"</item>
+    <item msgid="4221763391123233270">"Konektado"</item>
+    <item msgid="624838831631122137">"Suspendido"</item>
+    <item msgid="7979680559596111948">"Nadidiskonekta…"</item>
+    <item msgid="1634960474403853625">"Hindi nakakonekta"</item>
+    <item msgid="746097431216080650">"Hindi tagumpay"</item>
+    <item msgid="6367044185730295334">"Naka-block"</item>
+    <item msgid="503942654197908005">"Pansamantalang iniiwasan ang mabagal na koneksyon"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Nag-ii-scan…"</item>
+    <item msgid="355508996603873860">"Kumukonekta sa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="554971459996405634">"Nagpapatotoo sa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Pagkuha ng IP address mula sa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Nakakonekta sa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Suspendido"</item>
+    <item msgid="7698638434317271902">"Inaalis sa pagkakakonekta mula sa <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Hindi nakakonekta"</item>
+    <item msgid="8578370891960825148">"Hindi tagumpay"</item>
+    <item msgid="5660739516542454527">"Naka-block"</item>
+    <item msgid="1805837518286731242">"Pansamantalang iniiwasan ang mabagal na koneksyon"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
new file mode 100644
index 0000000..4519773
--- /dev/null
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Hindi makapag-scan ng mga network"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Wala"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Na-save"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Hindi Pinagana"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Pagkabigo ng Configuration ng IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Pagkabigo ng Koneksyon sa WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Problema sa pagpapatotoo"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Wala sa sakop"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Walang Natukoy na Access sa Internet, hindi awtomatikong muling kumonekta."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Na-save ni <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Nakakonekta sa pamamagitan ng Wi‑Fi assistant"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Nakakonekta sa pamamagitan ng %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Available sa pamamagitan ng %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Nakakonekta, walang Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Hindi nakakonekta"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Nadidiskonekta..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Kumukonekta…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Konektado"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Pinapares…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Nakakonekta (walang telepono)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Nakakonekta (walang media)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Nakakonekta (walang access sa mensahe)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Nakakonekta (walang telepono o media)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Audio ng media"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Audio ng telepono"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Paglilipat ng file"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Device sa pag-input"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Access sa internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Pagbabahagi ng contact"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Gamitin para sa pagbabahagi ng contact"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Pagbabahagi ng koneksyon sa internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Access sa Mensahe"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Access sa SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Konektado sa media audio"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Nakakonekta sa audio ng telepono"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Nakakonekta sa server sa paglilipat ng file"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Nakakonekta sa mapa"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Nakakonekta sa SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Hindi konektado sa server ng paglipat ng file"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Nakakonekta sa device ng input"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Konektado sa device sa Internet access"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Pagbahagi lokal koneksyon sa Internet sa device"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Gamitin para sa pag-access sa Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Gamitin para sa mapa"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Gamitin para sa pag-access sa SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Gamitin para sa media audio"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Ginagamit para sa audio ng telepono"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Ginagamit para sa paglilipat ng file"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Gamitin para sa input"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Pares"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"IPARES"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Kanselahin"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Nagbibigay ang pagpapares ng access sa iyong mga contact at history ng tawag kapag nakakonekta."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Hindi maipares sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Hindi maipares sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g> dahil sa maling PIN o passkey."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Hindi magawang makipag-ugnay sa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Tinanggihan ng <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ang pagpapares."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Naka-off ang Wifi."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Nakadiskonekta ang Wifi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"May isang bar ang Wifi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"May dalawang bar ang Wifi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"May tatlong bar ang Wifi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Puno ang signal ng Wifi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Mga inalis na app"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Mga inalis na apps at user"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Pag-tether sa USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Portable na hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Pag-tether ng Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Nagte-tether"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Pag-tether at portable hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Profile sa trabaho"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Bisita"</string>
+    <string name="unknown" msgid="1592123443519355854">"Hindi Kilala"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"User: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"May nakatakdang ilang default"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Walang nakatakdang mga default"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-tr/arrays.xml b/packages/SettingsLib/res/values-tr/arrays.xml
new file mode 100644
index 0000000..49d6839
--- /dev/null
+++ b/packages/SettingsLib/res/values-tr/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Taranıyor…"</item>
+    <item msgid="8513729475867537913">"Bağlanıyor…"</item>
+    <item msgid="515055375277271756">"Kimlik doğrulanıyor…"</item>
+    <item msgid="1943354004029184381">"IP adresi alınıyor..."</item>
+    <item msgid="4221763391123233270">"Bağlandı"</item>
+    <item msgid="624838831631122137">"Askıya alındı"</item>
+    <item msgid="7979680559596111948">"Bağlantı kesiliyor…"</item>
+    <item msgid="1634960474403853625">"Bağlantı kesildi"</item>
+    <item msgid="746097431216080650">"Başarısız"</item>
+    <item msgid="6367044185730295334">"Engellendi"</item>
+    <item msgid="503942654197908005">"Kötü bağlantıdan geçici olarak kaçınılıyor"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Taranıyor…"</item>
+    <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ağına bağlanılıyor…"</item>
+    <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> üzerinde kimlik doğrulanıyor…"</item>
+    <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ağından IP adresi alınıyor…"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> ağına bağlandı"</item>
+    <item msgid="1330262655415760617">"Askıya alındı"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> bağlantısı kesiliyor…"</item>
+    <item msgid="197508606402264311">"Bağlantı kesildi"</item>
+    <item msgid="8578370891960825148">"Başarısız"</item>
+    <item msgid="5660739516542454527">"Engellendi"</item>
+    <item msgid="1805837518286731242">"Kötü bağlantıdan geçici olarak kaçınılıyor"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
new file mode 100644
index 0000000..1834c64
--- /dev/null
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ağlar taranamıyor"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Yok"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Kaydedildi"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Devre dışı"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP Yapılandırması Hatası"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Kablosuz Bağlantı Hatası"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Kimlik doğrulama sorunu"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Kapsama alanı dışında"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"İnternet Erişimi algılanmadı, otomatik olarak tekrar bağlanmayacak."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tarafından kaydedildi"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Kablosuz bağlantı yardımcısıyla bağlandı"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s üzerinden bağlı"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s üzerinden kullanılabilir"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Bağlı, İnternet yok"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Bağlantı kesildi"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Bağlantı kesiliyor…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Bağlanıyor…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Bağlandı"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Eşleştiriliyor…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Bağlandı (telefon yok)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Bağlandı (medya yok)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Bağlı (mesaj erişimi yok)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Bağlandı (telefon veya medya yok)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Medya sesi"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefon sesi"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dosya aktarımı"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Giriş cihazı"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"İnternet erişimi"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kişi paylaşma"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Kişi paylaşmak için kullan"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"İnternet bağlantısı paylaşımı"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Mesaj Erişimi"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM Erişimi"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Medya sesine bağlanıldı"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon sesine bağlandı"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Dosya aktarım sunucusuna bağlandı"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"MAP\'ye bağlı"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"SAP\'ye bağlı"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Dosya aktarım sunucusuna bağlanmadı"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Giriş cihazına bağlı"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"İnternet erişimi için cihaza bağlandı"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Cihazla yerel Intrnt bağlantısını paylaşıyor"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"İnternet erişimi için kullan"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"MAP için kullan"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM erişimi için kullan"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Medya sesi için kullan"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Telefon sesi için kullan"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Dosya aktarımı için kullan"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Giriş için kullan"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Eşleştir"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"EŞLEŞTİR"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"İptal"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Eşleme işlemi, bağlantı kurulduğunda kişilerinize ve çağrı geçmişine erişim izni verir."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"PIN veya parola yanlış olduğundan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile eşleştirilemedi"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> ile iletişim kurulamıyor."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Eşleştirme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tarafından reddedildi."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Kablosuz kapalı."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Kablosuz bağlantı kesildi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Kablosuz sinyal gücü tek çubuk."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Kablosuz sinyal gücü iki çubuk."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Kablosuz sinyal gücü üç çubuk."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Kablosuz sinyal gücü tam."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android İS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Kaldırılan uygulamalar"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Kaldırılmış kullanıcılar ve uygulamalar"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB tethering"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Taşınabilir hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth tethering"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Tethering"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Tethering ve taşnblr hotspot"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"İş profili"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Misafir"</string>
+    <string name="unknown" msgid="1592123443519355854">"Bilinmiyor"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Kullanıcı: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Bazı varsayılan tercihler ayarlandı"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Hiçbir varsayılan tercih ayarlanmadı"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-uk/arrays.xml b/packages/SettingsLib/res/values-uk/arrays.xml
new file mode 100644
index 0000000..a5608b4
--- /dev/null
+++ b/packages/SettingsLib/res/values-uk/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"Підключення…"</item>
+    <item msgid="515055375277271756">"Автентифікація…"</item>
+    <item msgid="1943354004029184381">"Отримання ІР-адреси…"</item>
+    <item msgid="4221763391123233270">"Підключено"</item>
+    <item msgid="624838831631122137">"Припинено"</item>
+    <item msgid="7979680559596111948">"Відключення..."</item>
+    <item msgid="1634960474403853625">"Роз’єднано"</item>
+    <item msgid="746097431216080650">"Помилка"</item>
+    <item msgid="6367044185730295334">"Заблоковано"</item>
+    <item msgid="503942654197908005">"Тимчасове уникнення слабкого з’єднання"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>..."</item>
+    <item msgid="8937994881315223448">"Підключено до <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Призупинено"</item>
+    <item msgid="7698638434317271902">"Відключення від <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Роз’єднано"</item>
+    <item msgid="8578370891960825148">"Помилка"</item>
+    <item msgid="5660739516542454527">"Заблоковано"</item>
+    <item msgid="1805837518286731242">"Тимчасове уникнення слабкого з’єднання"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
new file mode 100644
index 0000000..ca273ae
--- /dev/null
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Неможливо здійснити сканування мереж"</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_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>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Не в діапазоні"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Немає доступу до Інтернету. Спроба під’єднання не здійснюватиметься автоматично."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Збережено додатком <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Під’єднано через Диспетчер Wi-Fi-з’єднання"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Під’єднано через %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Доступ через %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Під’єднано, але немає доступу до Інтернету"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Роз’єднано"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Відключення..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Підключення…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Підключено"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Підключення…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Під’єднано (без телефону)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Під’єднано (без медіа-файлів)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Під’єднано (без доступу до повідомлень)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Під’єднано (без телефону чи медіа)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Звук медіа-файлів"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Звук телефону"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Передавання файлів"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Пристрій введення"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Доступ до Інтернету"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Надсилання контактів"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Використовувати для надсилання контактів"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Надання доступу до Інтернету"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Доступ до повідомлень"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Доступ до SIM-карти"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Підключено до аудіоджерела"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Підключено до звуку телеф."</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Підключ. до сервера передачі файлів"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Під’єднано до карти"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Під’єднано до точки доступу"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Не підключ. до сервера передачі файлів"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Підключено до пристрою введ."</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Під’єдн. до пристр. для дост.до Інтерн."</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Доступ до локал.з’єдн. з Інтерн. ч-з пристрій"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Використовувати для доступу до Інтернету"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Використовувати для карти"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Використовувати для доступу до SIM-карти"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Викор. для аудіоджер."</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Викор. для звуку тел."</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Викор. для перед. файлів"</string>
+    <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_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-код чи ключ доступу."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Неможливо зв’язатися з пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Створ. пари відхилено <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi вимкнено."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi від’єднано."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Одна смужка сигналу Wi-Fi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Дві смужки сигналу Wi-Fi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Три смужки сигналу Wi-Fi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Максимальний сигнал Wi-Fi."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"ОС Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Видалені програми"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Видалені програми та користувачі"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Прив\'язка USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Порт. точка дост."</string>
+    <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="8101244883654409696">"Робочий профіль"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Гість"</string>
+    <string name="unknown" msgid="1592123443519355854">"Невідомо"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Користувач: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/arrays.xml b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
new file mode 100644
index 0000000..c58a4a7
--- /dev/null
+++ b/packages/SettingsLib/res/values-ur-rPK/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"مربوط ہو رہا ہے…"</item>
+    <item msgid="515055375277271756">"توثیق ہو رہی ہے…"</item>
+    <item msgid="1943354004029184381">"‏IP پتہ حاصل کر رہا ہے…"</item>
+    <item msgid="4221763391123233270">"مربوط ہو گیا"</item>
+    <item msgid="624838831631122137">"معطل شدہ"</item>
+    <item msgid="7979680559596111948">"منقطع کیا جارہا ہے…"</item>
+    <item msgid="1634960474403853625">"منقطع ہو گیا"</item>
+    <item msgid="746097431216080650">"ناکام"</item>
+    <item msgid="6367044185730295334">"مسدود"</item>
+    <item msgid="503942654197908005">"عارضی طور پر خراب کنکشن سے اجتناب کر رہا ہے"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے مربوط ہو گیا"</item>
+    <item msgid="1330262655415760617">"معطل شدہ"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> سے منقطع ہو رہا ہے…"</item>
+    <item msgid="197508606402264311">"منقطع ہو گیا"</item>
+    <item msgid="8578370891960825148">"ناکام"</item>
+    <item msgid="5660739516542454527">"مسدود ہے"</item>
+    <item msgid="1805837518286731242">"عارضی طور پر خراب کنکشن سے اجتناب کر رہا ہے"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
new file mode 100644
index 0000000..bdf50e0
--- /dev/null
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"نیٹ ورکس کیلئے اسکین نہيں کر سکتے ہیں"</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_network_failure" msgid="2364951338436007124">"‏IP کنفیگریشن کی ناکامی"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"‏WiFi کنکشن کی ناکامی"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"توثیق کا مسئلہ"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"رینج میں نہیں ہے"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"انٹرنیٹ تک کسی رسائی کا پتہ نہیں چلا، خود بخود دوبارہ منسلک نہیں ہوگا۔"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> کی جانب سے محفوظ کردہ"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"‏Wi‑Fi اسسٹنٹ کے ذریعے منسلک ہے"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"‏منسلک بذریعہ ‎%1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"‏دستیاب بذریعہ ‎%1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"منسلک، انٹرنیٹ نہیں ہے"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"منقطع"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"منقطع کیا جارہا ہے…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"مربوط ہو رہا ہے…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"مربوط"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"جوڑا بنایا جا رہا ہے…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"مربوط (کوئی فون نہیں ہے)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"مربوط (کوئی میڈیا نہیں ہے)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"مربوط (کسی پیغام تک رسائی نہیں ہے)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"مربوط (کوئی فون یا میڈیا نہیں ہے)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"میڈيا آڈیو"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"فون آڈیو"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"فائل کی منتقلی"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"ان پٹ آلہ"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"انٹرنیٹ تک رسائی"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"رابطہ کا اشتراک"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"رابطہ کے اشتراک کیلئے استعمال کریں"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"انٹرنیٹ کنکشن کا اشتراک کرنا"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"پیغام تک رسائی"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"‏SIM رسائی"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"میڈیا آڈیو سے مربوط"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"فون آڈیو سے مربوط"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"فائل منتقلی سرور سے مربوط ہو گیا ہے"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"نقشہ سے مربوط ہوگیا"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"‏SAP سے منسلک"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"فائل منتقلی سرور سے مربوط نہیں ہے"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"ان پٹ آلہ سے مربوط"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"انٹرنیٹ رسائی کیلئے آلہ سے مربوط ہو گیا"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"آلہ کے ساتھ مقامی انٹرنیٹ کنکشن کا اشتراک کر رہا ہے"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"انٹرنیٹ رسائی کیلئے استعمال"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"نقشہ کیلئے استعمال کریں"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"‏SIM رسائی کے لئے استعمال کریں"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"میڈیا آڈیو کیلئے استعمال کریں"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"فون آڈیو کیلئے استعمال کریں"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"فائل منتقل کرنے کیلئے استعمال کریں"</string>
+    <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_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">"‏غلط PIN یا پاس کلید کی وجہ سے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ جوڑا نہیں بنا سکا۔"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> کے ساتھ مواصلت نہیں ہو سکتی۔"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> نے جوڑا بنانے کو مسترد کر دیا۔"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"‏Wifi آف ہے۔"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"‏Wifi غیر منسلک ہو گیا۔"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"‏Wifi ایک بار۔"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"‏Wifi دو بارز۔"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"‏Wifi تین بارز۔"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"‏Wifi سگنل پورا ہے۔"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ہٹائی گئی ایپس"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ہٹائی گئی ایپس اور صارفین"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏USB مربوط کرنا"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"پورٹیبل ہاٹ اسپاٹ"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ مربوط کرنا"</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="8101244883654409696">"دفتر کا پروفائل"</string>
+    <string name="user_guest" msgid="8475274842845401871">"مہمان"</string>
+    <string name="unknown" msgid="1592123443519355854">"نامعلوم"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"صارف: <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>
+</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/arrays.xml b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
new file mode 100644
index 0000000..f2cae2c
--- /dev/null
+++ b/packages/SettingsLib/res/values-uz-rUZ/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Tekshirib chiqilmoqda…"</item>
+    <item msgid="8513729475867537913">"Ulanmoqda…"</item>
+    <item msgid="515055375277271756">"Tasdiqdan o‘tilmoqda…"</item>
+    <item msgid="1943354004029184381">"IP manzil o‘zlashtirilmoqda…"</item>
+    <item msgid="4221763391123233270">"Ulangan"</item>
+    <item msgid="624838831631122137">"Muzlatildi"</item>
+    <item msgid="7979680559596111948">"Uzilmoqda…"</item>
+    <item msgid="1634960474403853625">"Uzilgan"</item>
+    <item msgid="746097431216080650">"Muvaffaqiyatsiz"</item>
+    <item msgid="6367044185730295334">"To‘sib qo‘yilgan"</item>
+    <item msgid="503942654197908005">"Sifatsiz ulanishdan vaqtinchalik chetlashish"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Tekshirilmoqda…"</item>
+    <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘iga ulanilmoqda…"</item>
+    <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> bilan aloqa o‘rnatilyapti…"</item>
+    <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> IP manzil beryapti…"</item>
+    <item msgid="8937994881315223448">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘iga ulanildi"</item>
+    <item msgid="1330262655415760617">"Muzlatildi"</item>
+    <item msgid="7698638434317271902">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘idan uzilmoqda…"</item>
+    <item msgid="197508606402264311">"Uzildi"</item>
+    <item msgid="8578370891960825148">"Muvaffaqiyatsiz"</item>
+    <item msgid="5660739516542454527">"To‘sib qo‘yilgan"</item>
+    <item msgid="1805837518286731242">"Sifatsiz ulanishdan vaqtinchalik chetlashish"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
new file mode 100644
index 0000000..7761b657
--- /dev/null
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Tarmoqlarni tekshirib chiqishni iloji bo‘lmadi"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Yo‘q"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Saqlandi"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"O‘chiq"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP manzilini sozlab bo‘lmadi"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Wi-Fi ulanishini o‘rnatib bo‘lmadi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Tasdiqdan o‘tishda muammo"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Aloqada emas"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Internetga ulanish aniqlanmadi, avtomatik ravishda qayta ulana olmaydi."</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> tomonidan saqlangan"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Wi‑Fi yordamchisi orqali ulangan"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s orqali ulangan"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s orqali ishlaydi"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Ulangan, lekin internet aloqasi yo‘q"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Uzildi"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Uzilyapti…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Ulanmoqda…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Ulandi"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Biriktirilmoqda"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ulandi (telefondan tashqari)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ulanildi (mediadan tashqari)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Ulangan (xabarlarga kirib bo‘lmaydi)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ulangan (telefon yoki media qurilma emas)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Media audio"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Telefon audiosi"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Fayl o‘tkazish"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Kiritish qurilmasi"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Internetga kirish"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Kontaktlarni ulashish"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Kontaktlarni ulashish uchun ishlatilsin"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Internet aloqasi ulashmasi"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Xabarga kirish"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM-kartaga kirish"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Audio qurilmasiga ulangan"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Telefon karnayiga ulanildi"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Fayl almashinish serveriga ulanildi"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Xaritaga ulangan"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Ulanish nuqtasiga ulandi"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Fayl uzatish serveriga ulanmagan"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Kiritish qurilmasiga ulanildi"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Internet manbai qurilmasiga ulanildi"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Qurilmaga mahaliy internet aloqani tarqatish"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Internet manbai sifatida foydalanish"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Xaritada foydalanish"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"SIM-kartaga kirish uchun foydalanish"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Audio qurilma uchun foydalanish"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Dok’dan karnay sifatida foydalanish"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Fayl almashinish uchun foydalanish"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Kiritish qurilmasi sifatida foydalanish"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Biriktirish"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"ULANISH"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Bekor qilish"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Agar ulanishga ruxsat bersangiz, ulangan vaqtda kontakt va qo‘ng‘iroqlaringiz tarixiga kirishi mumkin."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> bilan biriktirib bo‘lmadi."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> qurilmasiga ulanib bo‘lmadi, chunki PIN-kod yoki parol noto‘g‘ri kiritildi."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Quyidagi qurilma javob bermayapti: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> biriktirish so‘rovini rad qildi."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi o‘chiq."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi o‘chirilgan."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi: bitta ustun"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi: ikkita ustun"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi: uchta ustun"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi: signal to‘liq"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"O‘chirilgan ilovalar"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"O‘chirib yuborilgan ilovalar va foydalanuvchilar"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB modem"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Ixcham hotspot"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Bluetooth modem"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Modem"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Modem rejimi"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Ishchi profil"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Mehmon"</string>
+    <string name="unknown" msgid="1592123443519355854">"Noma‘lum"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Foydalanuvchi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Ba’zi birlamchi sozlamalar o‘rnatilgan"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Birlamchi sozlamalar o‘rnatilmagan"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
new file mode 100644
index 0000000..26d32a9
--- /dev/null
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Đang quét…"</item>
+    <item msgid="8513729475867537913">"Đang kết nối…"</item>
+    <item msgid="515055375277271756">"Đang xác thực…"</item>
+    <item msgid="1943354004029184381">"Đang lấy địa chỉ IP…"</item>
+    <item msgid="4221763391123233270">"Đã kết nối"</item>
+    <item msgid="624838831631122137">"Bị tạm ngưng"</item>
+    <item msgid="7979680559596111948">"Đang ngắt kết nối…"</item>
+    <item msgid="1634960474403853625">"Đã ngắt kết nối"</item>
+    <item msgid="746097431216080650">"Không thành công"</item>
+    <item msgid="6367044185730295334">"Bị chặn"</item>
+    <item msgid="503942654197908005">"Tạm thời tránh kết nối kém"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Đang quét…"</item>
+    <item msgid="355508996603873860">"Đang kết nối tới <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="554971459996405634">"Đang xác thực với <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="7928343808033020343">"Đang lấy địa chỉ IP từ <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="8937994881315223448">"Đã kết nối tới <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Bị tạm ngưng"</item>
+    <item msgid="7698638434317271902">"Đăng ngắt kết nối khỏi <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Đã ngắt kết nối"</item>
+    <item msgid="8578370891960825148">"Không thành công"</item>
+    <item msgid="5660739516542454527">"Bị chặn"</item>
+    <item msgid="1805837518286731242">"Tạm thời tránh kết nối kém"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
new file mode 100644
index 0000000..3be2042
--- /dev/null
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Không thể dò tìm mạng"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Không"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Đã lưu"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Đã tắt"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Lỗi cấu hình IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Lỗi kết nối WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Sự cố xác thực"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ngoài vùng phủ sóng"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Không phát hiện thấy truy cập Internet nào, mạng sẽ không được tự động kết nối lại."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Được lưu bởi <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Được kết nối qua trình hỗ trợ Wi‑Fi"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Được kết nối qua %1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Có sẵn qua %1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Đã kết nối, không có Internet"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Đã ngắt kết nối"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Đang ngắt kết nối…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Đang kết nối…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Đã kết nối"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Đang ghép nối…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Đã kết nối (không có điện thoại)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Đã kết nối (không có phương tiện)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Đã kết nối (không truy cập tin nhắn)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Đã k.nối (kg có ĐT hoặc p.tiện nào)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Âm thanh của phương tiện"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Âm thanh điện thoại"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Chuyển tệp"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Thiết bị đầu vào"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Truy cập Internet"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Chia sẻ liên hệ"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Sử dụng để chia sẻ liên hệ"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Chia sẻ kết nối internet"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Truy cập tin nhắn"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Quyền truy cập SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Đã kết nối với âm thanh phương tiện"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Đã kết nối với âm thanh điện thoại"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Đã kết nối với máy chủ chuyển tệp"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Đã kết nối với bản đồ"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Được kết nối với SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Chưa kết nối với máy chủ chuyển tệp"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Đã kết nối với thiết bị nhập"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Đã kết nối với thiết bị"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Chia sẻ kết nối Internet"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Sử dụng để truy cập Internet"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Sử dụng cho bản đồ"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Sử dụng để truy cập SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Sử dụng cho âm thanh phương tiện"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Sử dụng cho âm thanh điện thoại"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Sử dụng để chuyển tệp"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Sử dụng để nhập"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Ghép nối"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"GHÉP NỐI"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Hủy"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Ghép nối giúp bạn có thể truy cập danh bạ và nhật ký cuộc gọi của mình khi được kết nối."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Không thể ghép nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Không thể ghép nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g> do mã PIN hoặc mã xác nhận không đúng."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Không thể kết nối với <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ghép nối bị <xliff:g id="DEVICE_NAME">%1$s</xliff:g> từ chối."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Đã tắt Wi-Fi."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Đã ngắt kết nối Wi-Fi."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Tín hiệu Wi-Fi một vạch."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Tín hiệu Wi-Fi hai vạch."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Tín hiệu Wi-Fi ba vạch."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Tín hiệu Wi-Fi đủ."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Hệ điều hành Android"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Ứng dụng đã xóa"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Ứng dụng và người dùng bị xóa"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Truy cập Internet qua USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Điểm phát sóng di động"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Truy cập Internet qua Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Đang dùng làm điểm truy cập Internet"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"USB Internet &amp; điểm truy cập di động"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Hồ sơ công việc"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Khách"</string>
+    <string name="unknown" msgid="1592123443519355854">"Không xác định"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Người dùng: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Đã đặt một số ứng dụng chạy mặc định"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Chưa đặt mặc định"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/arrays.xml b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
new file mode 100644
index 0000000..b7d99a1
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rCN/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"正在连接..."</item>
+    <item msgid="515055375277271756">"正在进行身份验证..."</item>
+    <item msgid="1943354004029184381">"正在获取IP地址..."</item>
+    <item msgid="4221763391123233270">"已连接"</item>
+    <item msgid="624838831631122137">"已暂停"</item>
+    <item msgid="7979680559596111948">"正在断开连接..."</item>
+    <item msgid="1634960474403853625">"已断开连接"</item>
+    <item msgid="746097431216080650">"失败"</item>
+    <item msgid="6367044185730295334">"已停用"</item>
+    <item msgid="503942654197908005">"暂时关闭(网络状况不佳)"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"已连接到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"已暂停"</item>
+    <item msgid="7698638434317271902">"正在断开与 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 的连接..."</item>
+    <item msgid="197508606402264311">"已断开连接"</item>
+    <item msgid="8578370891960825148">"失败"</item>
+    <item msgid="5660739516542454527">"已停用"</item>
+    <item msgid="1805837518286731242">"暂时关闭(网络状况不佳)"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..0031d39
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"无法扫描网络"</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_network_failure" msgid="2364951338436007124">"IP 配置失败"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WLAN 连接失败"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"身份验证出现问题"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"未检测到任何互联网连接,因此不会自动重新连接。"</string>
+    <string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"已连接(通过 WLAN 助手)"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"可通过%1$s连接"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已连接,但无法访问互联网"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"已断开连接"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在断开连接..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"正在连接..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"已连接"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"正在配对..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"已连接(无手机)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已连接(无媒体)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已连接(无消息权限)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已连接(没有手机或媒体信号)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒体音频"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"手机音频"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"文件传输"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"输入设备"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"互联网连接"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"共享联系人"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"用于共享联系人"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"共享互联网连接"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"消息权限"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取权限"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"已连接到媒体音频"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"已连接到手机音频"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已连接到文件传输服务器"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"已连接到地图"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已连接到 SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"未连接到文件传输服务器"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已连接到输入设备"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"经由其他设备连接到互联网"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"与其他设备共享该设备的互联网连接"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用于连接互联网"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"用于地图"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用于存取 SIM 卡"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用于媒体音频"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用于手机音频"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用于文件传输"</string>
+    <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_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">"PIN码或配对密钥不正确,无法与<xliff:g id="DEVICE_NAME">%1$s</xliff:g>配对。"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"无法与“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”进行通信。"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> 已拒绝配对。"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"WLAN 已关闭。"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"WLAN 连接已断开。"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"WLAN 信号强度为一格。"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"WLAN 信号强度为两格。"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"WLAN 信号强度为三格。"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"WLAN 信号满格。"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android 操作系统"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"已删除的应用"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已删除的应用和用户"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB网络共享"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"便携式热点"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"蓝牙网络共享"</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="8101244883654409696">"工作资料"</string>
+    <string name="user_guest" msgid="8475274842845401871">"访客"</string>
+    <string name="unknown" msgid="1592123443519355854">"未知"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"用户:<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>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/arrays.xml b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
new file mode 100644
index 0000000..b8a1ebb
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rHK/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"正在連線..."</item>
+    <item msgid="515055375277271756">"正在驗證…"</item>
+    <item msgid="1943354004029184381">"正在取得 IP 位址…"</item>
+    <item msgid="4221763391123233270">"已連線"</item>
+    <item msgid="624838831631122137">"已暫停"</item>
+    <item msgid="7979680559596111948">"正在中斷連線…"</item>
+    <item msgid="1634960474403853625">"已中斷連線"</item>
+    <item msgid="746097431216080650">"失敗"</item>
+    <item msgid="6367044185730295334">"已封鎖"</item>
+    <item msgid="503942654197908005">"目前正暫時避開欠佳的連線"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"已連線到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"已暫停"</item>
+    <item msgid="7698638434317271902">"正在中斷 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 連線…"</item>
+    <item msgid="197508606402264311">"已中斷連線"</item>
+    <item msgid="8578370891960825148">"失敗"</item>
+    <item msgid="5660739516542454527">"已封鎖"</item>
+    <item msgid="1805837518286731242">"目前正暫時避開欠佳的連線"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..2b41be3
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"無法掃瞄網絡"</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_network_failure" msgid="2364951338436007124">"IP 設定失敗"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"超出可用範圍"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"未能偵測到互聯網連線,因此不會自動重新連線。"</string>
+    <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> 的儲存"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi-Fi 小幫手連線"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 連線"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已連線,沒有互聯網"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"已中斷連線"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在中斷連線..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"正在連線..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"已連結"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"正在配對..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"已連線(無手機)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已連線 (無媒體)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已連結 (無訊息存取權)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已連線 (無手機或媒體)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒體音效"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"手機音效"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"檔案傳輸"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"輸入裝置"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"互聯網連線"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"聯絡人共用"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"用於聯絡人共用"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"互聯網連線分享"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"訊息存取權"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"已連接媒體音頻裝置"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"已連接手機耳機"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已連線至檔案傳輸伺服器"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"已連結地圖"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已連接 SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"未連線至檔案傳輸伺服器"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已連線至輸入裝置"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"已連線至裝置並取得互聯網連線"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"與裝置分享本地互聯網連線"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用於上網"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"用於地圖"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用來存取 SIM 卡"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用於媒體音效"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於手機音效"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string>
+    <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_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 碼或密鑰不正確。"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 通訊。"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」拒絕配對要求。"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi 已關閉。"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi 連線已中斷。"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi 訊號一格。"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi 訊號兩格。"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi 訊號三格。"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi 訊號滿格。"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android 作業系統"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"已移除的應用程式"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已移除的應用程式和使用者"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 網絡共享"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"可攜式熱點"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"藍牙網絡共享"</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="8101244883654409696">"公司檔案"</string>
+    <string name="user_guest" msgid="8475274842845401871">"訪客"</string>
+    <string name="unknown" msgid="1592123443519355854">"未知"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"使用者:<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>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/arrays.xml b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
new file mode 100644
index 0000000..ac1a5ad
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rTW/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    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="8513729475867537913">"連線中…"</item>
+    <item msgid="515055375277271756">"驗證中…"</item>
+    <item msgid="1943354004029184381">"正在取得 IP 位址…"</item>
+    <item msgid="4221763391123233270">"已連線"</item>
+    <item msgid="624838831631122137">"已暫停"</item>
+    <item msgid="7979680559596111948">"中斷連線中…"</item>
+    <item msgid="1634960474403853625">"已中斷連線"</item>
+    <item msgid="746097431216080650">"失敗"</item>
+    <item msgid="6367044185730295334">"已封鎖"</item>
+    <item msgid="503942654197908005">"目前正暫時避開品質不佳的連線"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></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>
+    <item msgid="8937994881315223448">"已連線到 <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"已暫停"</item>
+    <item msgid="7698638434317271902">"正在中斷 <xliff:g id="NETWORK_NAME">%1$s</xliff:g> 連線…"</item>
+    <item msgid="197508606402264311">"已中斷連線"</item>
+    <item msgid="8578370891960825148">"失敗"</item>
+    <item msgid="5660739516542454527">"已封鎖"</item>
+    <item msgid="1805837518286731242">"目前正暫時避開品質不佳的連線"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..6a1edf7
--- /dev/null
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"無法掃描網路"</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_network_failure" msgid="2364951338436007124">"IP 設定失敗"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"WiFi 連線失敗"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"驗證問題"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"不在有效範圍內"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"未偵測到可用的網際網路連線,系統無法為您自動重新連線。"</string>
+    <string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>儲存"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"已透過 Wi‑Fi 小幫手連線"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"已透過 %1$s 連線"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"可透過 %1$s 使用"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"已連線,沒有網際網路"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"已中斷連線"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"正在中斷連線…"</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"連線中…"</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"已連線"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"配對中…"</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"已連線 (無手機音訊)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"已連線 (無媒體音訊)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"已連線 (無訊息存取權)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"已連線 (無手機或媒體音訊)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"媒體音訊"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"手機音訊"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"檔案傳輸"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"輸入裝置"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"網際網路連線"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"聯絡人共用"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"用於聯絡人共用"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"網際網路連線分享"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"訊息存取權"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"SIM 卡存取權"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"連接至媒體音訊"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"連接至電話音訊"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"已連線到檔案傳輸伺服器"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"已連線至地圖"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"已連線到 SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"不要連線到檔案傳輸伺服器"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"已連線到輸入裝置"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"已連線至裝置並取得網際網路存取權"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"與裝置分享本地網際網路連線"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"用於網際網路連線"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"地圖使用偏好"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"用於 SIM 卡存取權"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"用於媒體音訊"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"用於電話音訊"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"用於傳輸檔案"</string>
+    <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_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 或密碼金鑰不正確。"</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"無法與 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 通訊。"</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」拒絕配對要求。"</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"已關閉 Wi-Fi。"</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi 連線已中斷。"</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wi-Fi 訊號強度一格。"</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Wi-Fi 訊號強度兩格。"</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Wi-Fi 訊號強度三格。"</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Wi-Fi 訊號強度滿格。"</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"Android 作業系統"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"移除的應用程式"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"已移除的應用程式和使用者"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB 網路共用"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"可攜式無線基地台"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"藍牙網路共用"</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="8101244883654409696">"工作設定檔"</string>
+    <string name="user_guest" msgid="8475274842845401871">"訪客"</string>
+    <string name="unknown" msgid="1592123443519355854">"不明"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"使用者:<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>
+</resources>
diff --git a/packages/SettingsLib/res/values-zu/arrays.xml b/packages/SettingsLib/res/values-zu/arrays.xml
new file mode 100644
index 0000000..3404563
--- /dev/null
+++ b/packages/SettingsLib/res/values-zu/arrays.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wifi_status">
+    <item msgid="1922181315419294640"></item>
+    <item msgid="8934131797783724664">"Iyathwebula..."</item>
+    <item msgid="8513729475867537913">"Iyaxhuma kwi-inthanethi..."</item>
+    <item msgid="515055375277271756">"Iyaqinisekisa..."</item>
+    <item msgid="1943354004029184381">"Ithola ikheli le-IP..."</item>
+    <item msgid="4221763391123233270">"Ixhunyiwe kwi-inthanethi"</item>
+    <item msgid="624838831631122137">"Kumiswe okwesikhashana"</item>
+    <item msgid="7979680559596111948">"Inqamula uxhumano kwi-inthanethi..."</item>
+    <item msgid="1634960474403853625">"Ayixhunyiwe"</item>
+    <item msgid="746097431216080650">"Akuphumelelanga"</item>
+    <item msgid="6367044185730295334">"Uvinjelwe"</item>
+    <item msgid="503942654197908005">"Okwesikhashana ivikela ukuxhumana okungaqinile"</item>
+  </string-array>
+  <string-array name="wifi_status_with_ssid">
+    <item msgid="7714855332363650812"></item>
+    <item msgid="8878186979715711006">"Iyathwebula..."</item>
+    <item msgid="355508996603873860">"Ixhuma ku-<xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="554971459996405634">"Iqinisekisa nge <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="7928343808033020343">"Ithola ikheli le-IP kusuka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>..."</item>
+    <item msgid="8937994881315223448">"Ixhumeke ku-<xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
+    <item msgid="1330262655415760617">"Kumiswe okwesikhashana"</item>
+    <item msgid="7698638434317271902">"Inqamula kusuka <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+    <item msgid="197508606402264311">"Ayixhunyiwe kwi-inthanethi"</item>
+    <item msgid="8578370891960825148">"Akuphumelelanga"</item>
+    <item msgid="5660739516542454527">"Uvinjelwe"</item>
+    <item msgid="1805837518286731242">"Okwesikhashana ivikela ukuxhumana okungaqinile"</item>
+  </string-array>
+</resources>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
new file mode 100644
index 0000000..83e3dc9
--- /dev/null
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+**
+** Copyright 2015 The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="wifi_fail_to_scan" msgid="1265540342578081461">"Ayikwazi ukuhlola amanethiwekhi"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Lutho"</string>
+    <string name="wifi_remembered" msgid="4955746899347821096">"Kulondoloziwe"</string>
+    <string name="wifi_disabled_generic" msgid="4259794910584943386">"Akusebenzi"</string>
+    <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Ukwehluleka kokulungiswa kwe-IP"</string>
+    <string name="wifi_disabled_wifi_failure" msgid="3081668066612876581">"Ukwehlulekla koxhumo le-WiFi"</string>
+    <string name="wifi_disabled_password_failure" msgid="8659805351763133575">"Inkinga yokufakazela ubuqiniso"</string>
+    <string name="wifi_not_in_range" msgid="1136191511238508967">"Ayikho ebubanzini"</string>
+    <string name="wifi_no_internet" msgid="9151470775868728896">"Ukufinyeela okungekhona kwe-inthanethi kutholakele, ngeke kuxhumeke ngokuzenzakalelayo."</string>
+    <string name="saved_network" msgid="4352716707126620811">"Kulondolozwe ngu-<xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="connected_via_wfa" msgid="3805736726317410714">"Ixhunywe ngomsizi we-Wi-FI"</string>
+    <string name="connected_via_passpoint" msgid="2826205693803088747">"Kuxhumeke nge-%1$s"</string>
+    <string name="available_via_passpoint" msgid="1617440946846329613">"Iyatholakala nge-%1$s"</string>
+    <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Kuxhumekile, ayikho i-inthanethi"</string>
+    <string name="bluetooth_disconnected" msgid="6557104142667339895">"Ayixhunyiwe"</string>
+    <string name="bluetooth_disconnecting" msgid="8913264760027764974">"Inqamula uxhumano kwi-inthanethi..."</string>
+    <string name="bluetooth_connecting" msgid="8555009514614320497">"Iyaxhuma..."</string>
+    <string name="bluetooth_connected" msgid="6038755206916626419">"Ixhunyiwe"</string>
+    <string name="bluetooth_pairing" msgid="1426882272690346242">"Iyabhangqa..."</string>
+    <string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"Ixhunyiwe (ayikho ifoni)"</string>
+    <string name="bluetooth_connected_no_a2dp" msgid="4576188601581440337">"Ixhunyiwe (ayikho imidiya)"</string>
+    <string name="bluetooth_connected_no_map" msgid="6504436917057479986">"Kuxhunyiwe (akukho ukufinyelela umlayezo)"</string>
+    <string name="bluetooth_connected_no_headset_no_a2dp" msgid="9195757766755553810">"Ixhunyiwe (ayikho ifoni noma imidiya)"</string>
+    <string name="bluetooth_profile_a2dp" msgid="2031475486179830674">"Umsindo wemidiya"</string>
+    <string name="bluetooth_profile_headset" msgid="8658779596261212609">"Umsindo wefoni"</string>
+    <string name="bluetooth_profile_opp" msgid="9168139293654233697">"Dlulisa ifayela"</string>
+    <string name="bluetooth_profile_hid" msgid="3680729023366986480">"Idivaysi yokufakwayo"</string>
+    <string name="bluetooth_profile_pan" msgid="3391606497945147673">"Ukufinyelela i-Inthanethi"</string>
+    <string name="bluetooth_profile_pbap" msgid="5372051906968576809">"Ukwabelana kokuxhumana"</string>
+    <string name="bluetooth_profile_pbap_summary" msgid="6605229608108852198">"Sebenzisela ukwabelana kokuxhumana"</string>
+    <string name="bluetooth_profile_pan_nap" msgid="8429049285027482959">"Ukwabelana ngoxhumano lwe-Inthanethi"</string>
+    <string name="bluetooth_profile_map" msgid="5465271250454324383">"Ukufinyelela umlayezo"</string>
+    <string name="bluetooth_profile_sap" msgid="5764222021851283125">"Ukufinyelela kwe-SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_connected" msgid="963376081347721598">"Ixhume emsindweni wemidiya"</string>
+    <string name="bluetooth_headset_profile_summary_connected" msgid="7661070206715520671">"Ixhunywe kumsindo wefoni"</string>
+    <string name="bluetooth_opp_profile_summary_connected" msgid="2611913495968309066">"Ixhunywe kwiseva yokudlulisa ifayela"</string>
+    <string name="bluetooth_map_profile_summary_connected" msgid="8191407438851351713">"Ixhumeke kumephu"</string>
+    <string name="bluetooth_sap_profile_summary_connected" msgid="8561765057453083838">"Kuxhumeke ku-SAP"</string>
+    <string name="bluetooth_opp_profile_summary_not_connected" msgid="1267091356089086285">"Ayixhunyiwe kwiseva sokudlulisa ifayela"</string>
+    <string name="bluetooth_hid_profile_summary_connected" msgid="3381760054215168689">"Ixhunywe kwidivaysi yokufakwayo"</string>
+    <string name="bluetooth_pan_user_profile_summary_connected" msgid="4602294638909590612">"Ixhunyiwe kwidivaysi yokufinyelela kwi-Inthanethi"</string>
+    <string name="bluetooth_pan_nap_profile_summary_connected" msgid="1561383706411975199">"Yabelana noxhumano lwe-Inthanethi kanye nedivaysi"</string>
+    <string name="bluetooth_pan_profile_summary_use_for" msgid="5664884523822068653">"Sebenzisa ukufinyelela i-Inthanethi"</string>
+    <string name="bluetooth_map_profile_summary_use_for" msgid="5154200119919927434">"Sebenzisela imephu"</string>
+    <string name="bluetooth_sap_profile_summary_use_for" msgid="7085362712786907993">"Ukusebenzisa kokufinyelela kwe-SIM"</string>
+    <string name="bluetooth_a2dp_profile_summary_use_for" msgid="4630849022250168427">"Sebenzisela umsindo wemidiya"</string>
+    <string name="bluetooth_headset_profile_summary_use_for" msgid="8705753622443862627">"Sebenziselwa umsindo wefoni"</string>
+    <string name="bluetooth_opp_profile_summary_use_for" msgid="1255674547144769756">"Sebenziselwa ukudlulisa ifayela"</string>
+    <string name="bluetooth_hid_profile_summary_use_for" msgid="232727040453645139">"Isetshenziselwa okufakwayo"</string>
+    <string name="bluetooth_pairing_accept" msgid="6163520056536604875">"Bhangqa"</string>
+    <string name="bluetooth_pairing_accept_all_caps" msgid="6061699265220789149">"BHANQA"</string>
+    <string name="bluetooth_pairing_decline" msgid="4185420413578948140">"Khansela"</string>
+    <string name="bluetooth_pairing_will_share_phonebook" msgid="4982239145676394429">"Ukubhanqa kunika ukufinyelela koxhumana nabo nomlando wekholi uma uxhumekile."</string>
+    <string name="bluetooth_pairing_error_message" msgid="3748157733635947087">"Ayikwazanga ukuhlangana ne <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Ayikwazanga ukumataniswa ne <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ngenxa ye-PIN noma isihluthulelo sokungena okungafanele."</string>
+    <string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Ayaikwazi ukuxhumana ne- <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Ukubhangqa kunqatshelwe i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+    <string name="accessibility_wifi_off" msgid="1166761729660614716">"I-Wifi ivaliwe."</string>
+    <string name="accessibility_no_wifi" msgid="8834610636137374508">"I-Wifi inqanyuliwe."</string>
+    <string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Ibha elilodwa le-Wifi."</string>
+    <string name="accessibility_wifi_two_bars" msgid="3569851234710034416">"Amabha amabili we-Wifi."</string>
+    <string name="accessibility_wifi_three_bars" msgid="8134185644861380311">"Amabha amathathu we-Wifi."</string>
+    <string name="accessibility_wifi_signal_full" msgid="7061045677694702">"Isiginali ye-Wifi igcwele."</string>
+    <string name="process_kernel_label" msgid="3916858646836739323">"I-Android OS"</string>
+    <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Izinhlelo zokusebenza zisusiwe"</string>
+    <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Izinhelo zokusebenza nabasebenzisi abasusiwe"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Imodemu nge-USB"</string>
+    <string name="tether_settings_title_wifi" msgid="3277144155960302049">"I-hotspot ephathekayo"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Imodemu nge-Bluetooth"</string>
+    <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Ukusebenzisa njengemodemu"</string>
+    <string name="tether_settings_title_all" msgid="8356136101061143841">"Ukusebenzisa njengemodemu &amp; i-hotspot ephathekayo"</string>
+    <string name="managed_user_title" msgid="8101244883654409696">"Iphrofayela yomsebenzi"</string>
+    <string name="user_guest" msgid="8475274842845401871">"Isivakashi"</string>
+    <string name="unknown" msgid="1592123443519355854">"Akwaziwa"</string>
+    <string name="running_process_item_user_label" msgid="3129887865552025943">"Umsebenzisi: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
+    <string name="launch_defaults_some" msgid="313159469856372621">"Okunye okuzenzakalelayo okusethiwe"</string>
+    <string name="launch_defaults_none" msgid="4241129108140034876">"Akukho okuzenzakalelayo okusethiwe"</string>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9b1f103..c44a7960 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -225,4 +225,10 @@
 
     <!-- [CHAR LIMIT=NONE] Label of a running process that represents another user -->
     <string name="running_process_item_user_label">User: <xliff:g id="user_name">%1$s</xliff:g></string>
+
+    <!-- Launch defaults preference summary with some set [CHAR LIMIT=40] -->
+    <string name="launch_defaults_some">Some defaults set</string>
+    <!-- Launch defaults preference summary with none set [CHAR LIMIT=40] -->
+    <string name="launch_defaults_none">No defaults set</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
new file mode 100644
index 0000000..cf17ea5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.accessibility;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+public class AccessibilityUtils {
+    public static final char ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR = ':';
+
+    final static TextUtils.SimpleStringSplitter sStringColonSplitter =
+            new TextUtils.SimpleStringSplitter(ENABLED_ACCESSIBILITY_SERVICES_SEPARATOR);
+
+    /**
+     * @return the set of enabled accessibility services. If there are not services
+     * it returned the unmodifiable {@link Collections#emptySet()}.
+     */
+    public static Set<ComponentName> getEnabledServicesFromSettings(Context context) {
+        final String enabledServicesSetting = Settings.Secure.getString(
+                context.getContentResolver(), Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES);
+        if (enabledServicesSetting == null) {
+            return Collections.emptySet();
+        }
+
+        final Set<ComponentName> enabledServices = new HashSet<ComponentName>();
+        final TextUtils.SimpleStringSplitter colonSplitter = sStringColonSplitter;
+        colonSplitter.setString(enabledServicesSetting);
+
+        while (colonSplitter.hasNext()) {
+            final String componentNameString = colonSplitter.next();
+            final ComponentName enabledService = ComponentName.unflattenFromString(
+                    componentNameString);
+            if (enabledService != null) {
+                enabledServices.add(enabledService);
+            }
+        }
+
+        return enabledServices;
+    }
+
+    /**
+     * @return a localized version of the text resource specified by resId
+     */
+    public static CharSequence getTextForLocale(Context context, Locale locale, int resId) {
+        final Resources res = context.getResources();
+        final Configuration config = new Configuration(res.getConfiguration());
+        config.setLocale(locale);
+        final Context langContext = context.createConfigurationContext(config);
+        return langContext.getText(resId);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
new file mode 100644
index 0000000..344bf62
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.settingslib.applications;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class AppUtils {
+    private static final String TAG = "AppUtils";
+
+    public static CharSequence getLaunchByDefaultSummary(ApplicationsState.AppEntry appEntry,
+            IUsbManager usbManager, PackageManager pm, Context context) {
+        String packageName = appEntry.info.packageName;
+        boolean hasPreferred = hasPreferredActivities(pm, packageName)
+                || hasUsbDefaults(usbManager, packageName);
+        int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId());
+        // consider a visible current link-handling state to be any explicitly designated behavior
+        boolean hasDomainURLsPreference =
+                status != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
+        return context.getString(hasPreferred || hasDomainURLsPreference
+                ? R.string.launch_defaults_some
+                : R.string.launch_defaults_none);
+    }
+
+    public static boolean hasUsbDefaults(IUsbManager usbManager, String packageName) {
+        try {
+            if (usbManager != null) {
+                return usbManager.hasDefaults(packageName, UserHandle.myUserId());
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "mUsbManager.hasDefaults", e);
+        }
+        return false;
+    }
+
+    public static boolean hasPreferredActivities(PackageManager pm, String packageName) {
+        // Get list of preferred activities
+        List<ComponentName> prefActList = new ArrayList<>();
+        // Intent list cannot be null. so pass empty list
+        List<IntentFilter> intentList = new ArrayList<>();
+        pm.getPreferredActivities(intentList, prefActList, packageName);
+        Log.d(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
+        return prefActList.size() > 0;
+    }
+
+}
diff --git a/packages/Shell/res/values-sv/strings.xml b/packages/Shell/res/values-sv/strings.xml
index 47ee2f7..8b72938 100644
--- a/packages/Shell/res/values-sv/strings.xml
+++ b/packages/Shell/res/values-sv/strings.xml
@@ -18,7 +18,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_label" msgid="3701846017049540910">"Skal"</string>
     <string name="bugreport_finished_title" msgid="2293711546892863898">"Felrapporten har skapats"</string>
-    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Dra till vänster om du vill dela felrapporten"</string>
+    <string name="bugreport_finished_text" product="watch" msgid="8389172248433597683">"Svep åt vänster om du vill dela felrapporten"</string>
     <string name="bugreport_finished_text" product="default" msgid="3559904746859400732">"Tryck om du vill dela felrapporten"</string>
     <string name="bugreport_confirm" msgid="5130698467795669780">"Felrapporter innehåller data från systemets olika loggfiler, inklusive personliga och privata uppgifter. Dela bara felrapporter med personer du litar på."</string>
     <string name="bugreport_confirm_repeat" msgid="4926842460688645058">"Visa det här meddelandet nästa gång"</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index d83b516..0d1ad19 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -25,6 +25,7 @@
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
+import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -41,14 +42,11 @@
 import libcore.io.Streams;
 
 import java.io.BufferedOutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.Closeable;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 import java.util.ArrayList;
@@ -107,11 +105,6 @@
      */
     private void triggerLocalNotification(final Context context, final File bugreportFile,
             final File screenshotFile) {
-        // Files are kept on private storage, so turn into Uris that we can
-        // grant temporary permissions for.
-        final Uri bugreportUri = FileProvider.getUriForFile(context, AUTHORITY, bugreportFile);
-        final Uri screenshotUri = FileProvider.getUriForFile(context, AUTHORITY, screenshotFile);
-
         boolean isPlainText = bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
@@ -133,12 +126,22 @@
      */
     private static Intent buildSendIntent(Context context, Uri bugreportUri, Uri screenshotUri) {
         final Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
+        final String mimeType = "application/vnd.android.bugreport";
         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
-        intent.setType("application/vnd.android.bugreport");
+        intent.setType(mimeType);
 
         intent.putExtra(Intent.EXTRA_SUBJECT, bugreportUri.getLastPathSegment());
+
+        // EXTRA_TEXT should be an ArrayList, but some clients are expecting a single String.
+        // So, to avoid an exception on Intent.migrateExtraStreamToClipData(), we need to manually
+        // create the ClipData object with the attachments URIs.
         intent.putExtra(Intent.EXTRA_TEXT, SystemProperties.get("ro.build.description"));
+        final ClipData clipData = new ClipData(
+                null, new String[] { mimeType },
+                new ClipData.Item(null, null, null, bugreportUri));
+        clipData.addItem(new ClipData.Item(null, null, null, screenshotUri));
+        intent.setClipData(clipData);
 
         final ArrayList<Uri> attachments = Lists.newArrayList(bugreportUri, screenshotUri);
         intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, attachments);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 5d622a0..be5c0fe 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -214,6 +214,7 @@
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
                   android:resizeableActivity="true"
+                  android:configChanges="orientation|screenSize|smallestScreenSize"
                   android:theme="@style/RecentsTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
diff --git a/packages/SystemUI/res/drawable/ic_collapse_children.xml b/packages/SystemUI/res/drawable/ic_collapse_children.xml
deleted file mode 100644
index b0ce1e6..0000000
--- a/packages/SystemUI/res/drawable/ic_collapse_children.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetTop="2dp"
-       android:drawable="@drawable/ic_expand_less"/>
diff --git a/packages/SystemUI/res/drawable/ic_expand_children.xml b/packages/SystemUI/res/drawable/ic_expand_children.xml
deleted file mode 100644
index 1762be4..0000000
--- a/packages/SystemUI/res/drawable/ic_expand_children.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-       android:insetTop="2dp"
-       android:drawable="@drawable/ic_expand_more"/>
diff --git a/packages/SystemUI/res/drawable/notification_expand_more.xml b/packages/SystemUI/res/drawable/notification_expand_more.xml
new file mode 100644
index 0000000..5aa7937
--- /dev/null
+++ b/packages/SystemUI/res/drawable/notification_expand_more.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="22.0dp"
+    android:height="22.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:pathData="M16.600000,8.600000l-4.600000,4.599999 -4.600000,-4.599999 -1.400000,1.400000 6.000000,6.000000 6.000000,-6.000000z"
+        android:fillColor="#FF000000"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/hybrid_notification.xml b/packages/SystemUI/res/layout/hybrid_notification.xml
new file mode 100644
index 0000000..9e64d2c
--- /dev/null
+++ b/packages/SystemUI/res/layout/hybrid_notification.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.systemui.statusbar.notification.HybridNotificationView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_max_height">
+    <TextView
+        android:id="@+id/notification_title"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:singleLine="true"
+        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
+        android:paddingEnd="4dp"
+    />
+    <TextView
+        android:id="@+id/notification_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_vertical"
+        android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+        android:singleLine="true"
+        />
+</com.android.systemui.statusbar.notification.HybridNotificationView>
diff --git a/packages/SystemUI/res/layout/notification_collapse_button.xml b/packages/SystemUI/res/layout/notification_collapse_button.xml
deleted file mode 100644
index 3ec5f63..0000000
--- a/packages/SystemUI/res/layout/notification_collapse_button.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_bottom_decor_height">
-    <TextView
-        android:id="@+id/notification_expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/notification_bottom_decor_height"
-        android:background="@null"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="center_vertical|center_horizontal"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
-        android:text="@string/notification_collapse_button_text"
-        android:drawableEnd="@drawable/ic_collapse_children"
-        android:drawablePadding="1dp"
-        />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_expand_button.xml b/packages/SystemUI/res/layout/notification_expand_button.xml
deleted file mode 100644
index 3c478f7..0000000
--- a/packages/SystemUI/res/layout/notification_expand_button.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2015 The Android Open Source Project
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License
-  -->
-
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/notification_bottom_decor_height">
-    <TextView
-        android:id="@+id/notification_expand_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/notification_bottom_decor_height"
-        android:background="@null"
-        android:layout_gravity="top|center_horizontal"
-        android:gravity="center_vertical|center_horizontal"
-        android:textAppearance="@*android:style/TextAppearance.Material.Notification.Title"
-        android:text="@string/notification_expand_button_text"
-        android:drawableEnd="@drawable/ic_expand_children"
-        android:drawablePadding="1dp"
-        />
-    <com.android.systemui.statusbar.AlphaOptimizedView
-        android:id="@+id/notification_expand_divider"
-        android:layout_width="match_parent"
-        android:layout_height="1dp"
-        android:layout_gravity="top|center"
-        android:background="@*android:drawable/notification_template_divider" />
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/notification_header.xml b/packages/SystemUI/res/layout/notification_header.xml
new file mode 100644
index 0000000..3475d00
--- /dev/null
+++ b/packages/SystemUI/res/layout/notification_header.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<com.android.systemui.statusbar.notification.NotificationHeaderView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/notification_header_height"
+    android:clipChildren="false">
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="@dimen/notification_header_height"
+        android:layout_gravity="start"
+        android:gravity="center_vertical"
+        android:paddingStart="@dimen/notification_content_margin_start">
+        <ImageView
+            android:id="@+id/header_notification_icon"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_marginEnd="4dp"
+            />
+        <TextView
+            android:id="@+id/number_of_children"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@*android:style/TextAppearance.Material.Notification"
+            android:layout_marginEnd="2dp"
+            android:layout_marginStart="1dp"
+            />
+        <TextView
+            android:id="@+id/app_name_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginStart="4dp"
+            android:layout_marginEnd="8dp"
+            />
+        <TextView
+            android:id="@+id/app_title_sub_text_divider"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginEnd="8dp"
+            android:text="@string/notification_header_divider_symbol"/>
+        <TextView
+            android:id="@+id/title_sub_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.Material.Notification.HeaderTitle"
+            android:layout_marginEnd="8dp" />
+        <TextView
+            android:id="@+id/post_time"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="end|center_vertical"
+            android:textAppearance="@*android:style/TextAppearance.Material.Notification.Time"
+            android:paddingEnd="8dp"
+            />
+    </LinearLayout>
+    <ImageButton
+        android:id="@+id/notification_expand_button"
+        android:background="@null"
+        android:layout_width="48dp"
+        android:layout_height="48dp"
+        android:layout_gravity="end|center_vertical"
+        android:src="@drawable/notification_expand_more"
+        android:layout_marginEnd="8dp"
+        />
+</com.android.systemui.statusbar.notification.NotificationHeaderView>
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 6187070..cc35c51c 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -35,18 +35,22 @@
     <com.android.systemui.qs.QuickQSPanel
         android:id="@+id/quick_qs_panel"
         android:background="#0000"
-        android:layout_width="142dp"
+        android:layout_width="144dp"
         android:layout_height="match_parent"
-        android:layout_alignParentEnd="true" />
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="12dp" />
 
     <LinearLayout
         android:id="@+id/expanded_group"
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
+        android:gravity="center"
         android:clipChildren="false"
         android:clipToPadding="false"
         android:orientation="horizontal"
-        android:layout_alignParentEnd="true">
+        android:layout_alignParentEnd="true"
+        android:layout_marginEnd="10dp">
+
         <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
             android:id="@+id/settings_button_container"
             android:layout_width="48dp"
@@ -74,7 +78,8 @@
 
         <ImageView
             android:layout_width="48dp"
-            android:layout_height="match_parent"
+            android:layout_height="48dp"
+            android:padding="12dp"
             android:src="@drawable/ic_expand_less"
             android:tint="@android:color/white" />
     </LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index ea7ce96..b9088ec 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -61,11 +61,11 @@
         />
 
     <ViewStub
-        android:layout="@layout/notification_expand_button"
-        android:id="@+id/more_button_stub"
-        android:inflatedId="@+id/notification_more_button_container"
+        android:layout="@layout/notification_header"
+        android:id="@+id/notification_header_stub"
+        android:inflatedId="@+id/notification_header"
         android:layout_width="match_parent"
-        android:layout_height="@dimen/notification_bottom_decor_height"
+        android:layout_height="@dimen/notification_header_height"
         />
 
     <ViewStub
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f50abf7..0e31d8d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Vou uit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Vou in"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skerm is vasgespeld"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig op dieselfde tyd om te ontspeld."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Dit hou dit in sig totdat jy ontspeld. Raak en hou Oorsig om te ontspeld."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Het dit"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, dankie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e507e64..ec6ec93 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"አስፋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ሰብስብ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ማያ ገጽ ተሰክቷል"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ይህ እስከሚነቅሉት ድረስ ድረስ በዕይታ ውስጥ እንዲቆይ ያደርገዋል። ለመንቀል በተመሳሳይ ጊዜ ተመለስን እና አጠቃላይ ዕይታን አንድ ላይ ነክተው ይያዙ።"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ይህ እስከሚነቅሉት ድረስ በዕይታ ውስጥ ያቆየዋል። እንዲነቀል ለማድረግ አጠቃላይ ዕይታን ነካ አድርገው ይያዙት።"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
     <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 1098af1..02fc3fe 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -397,8 +397,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"توسيع"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"تصغير"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"تم تثبيت الشاشة"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"يساعد هذا على استمرار العرض حتى يتم إلغاء التثبيت. ويمكنك لمس \"رجوع\" و\"عرض عام\" مع الاستمرار في وقت واحد لإلغاء التثبيت."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"يساعد هذا على استمرار العرض حتى يتم إلغاء التثبيت. ويمكنك لمس \"عرض عام\" مع الاستمرار في وقت واحد لإلغاء التثبيت."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -444,10 +444,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
     <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
     <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"تشغيل البلوتوث؟"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"لتوصيل لوحة المفاتيح بالجهاز اللوحي، يلزمك تشغيل بلوتوث أولاً."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"تشغيل"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 4b5309c..aba22f8 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişləndirin"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yığcamlaşdırın"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrana sancaq taxıldı"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Sancaq götürülənə qədər bu, görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə eyni vaxtda toxunun və saxlayın."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Sancaq götürülənə qədər bu, görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə toxunun və saxlayın."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yox, çox sağ olun"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivləşsin?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Tabletinizlə klaviaturaya bağlanmaq üçün ilk olaraq Bluetooth\'u aktivləşdirməlisiniz."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivləşdirin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 70cf7f8..50ac61f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгъване"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свиване"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранът е фиксиран"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Така екранът ще се показва, докато не го освободите. За да направите това, докоснете и задръжте бутона за връщане назад и този за общ преглед едновременно."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Така екранът ще се показва, докато не го освободите. За да направите това, докоснете и задръжте бутона за общ преглед."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index fd61c8b..f32cfcc 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"প্রসারিত করুন"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সঙ্কুচিত করুন"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্রীন পিন করা হয়েছে"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"এটি আপনার আনপিন না করা পর্যন্ত এটিকে দর্শনে রাখে৷ আনপিন করতে একই সময়ে ফিরুন এবং ওভারভিউ এ স্পর্শ করে ধরে রাখুন৷"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"এটি আপনার আনপিন না করা পর্যন্ত এটিকে দর্শনে রাখে৷ আনপিন করতে ওভারভিউ এ স্পর্শ করে ধরে রাখুন৷"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
     <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
     <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth চালু করবেন?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"আপনার ট্যাবলেটের সাথে আপনার কীবোর্ড সংযুক্ত করতে, আপনাকে প্রথমে Bluetooth চালু করতে হবে।"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"চালু করুন"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 8eac5d9..429f70b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Amplia"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Replega"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La pantalla està fixada"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Continuarà a la visualització fins que n\'anul·lis la fixació. Per fer-ho, toca i mantén premuts els botons Enrere i Visió general a la vegada."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Continuarà a la visualització fins que n\'anul·lis la fixació. Per fer-ho, toca i mantén premut el botó Visió general."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"D\'acord"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gràcies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -439,13 +439,10 @@
     <string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
-    <string name="qs_rearrange" msgid="8060918697551068765">"Torna a ordenar la Configuració ràpida"</string>
-    <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a la Configuració ràpida"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganitza Configuració ràpida"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a Configuració ràpida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e1b0256..ee77cf9 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -397,8 +397,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbalit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sbalit"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je připnuta"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Chcete-li jej uvolnit, stiskněte a podržte současně tlačítka Zpět a Přehled."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumím"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, děkuji"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -444,10 +444,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 745bf5a..f749756 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Udvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skærmen er fastgjort"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Dette fastholder den i visningen, indtil du frigør den. Tryk på Tilbage og Oversigt på samme tid, og hold dem nede for at frigøre denne skærm."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Dette fastholder den i visningen, indtil du frigør den. Tryk på Oversigt, og hold den nede for at frigøre denne skærm."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK, det er forstået"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 796cce2..cfaecaf 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Maximieren"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minimieren"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Zurück\" und \"Übersicht\" gleichzeitig, um die Fixierung aufzuheben."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Der Bildschirm wird solange angezeigt, bis Sie die Fixierung aufheben. Berühren und halten Sie \"Übersicht\", wenn Sie die Fixierung aufheben möchten."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 1dcfb7b..6fc1b59 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ανάπτυξη"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Σύμπτυξη"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Η οθόνη καρφιτσώθηκε"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Με αυτόν τον τρόπο παραμένει σε προβολή έως ότου την ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα \"Επιστροφή\" και \"Επισκόπηση\" ταυτόχρονα για ξεκαρφίτσωμα."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Με αυτόν τον τρόπο παραμένει σε προβολή έως ότου την ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
     <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index d991f16..ffdc3af7 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index d991f16..ffdc3af7 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index d991f16..ffdc3af7 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expand"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Collapse"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Screen is pinned"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"This keeps it in view until you unpin. Touch and hold Overview to unpin."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Got it"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, thanks"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Hide <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Turn on Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"To connect your keyboard with your tablet, you first have to turn on Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Turn on"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 4eef099..d4bb0a6 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fija"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Esta función mantiene fija la vista de la pantalla hasta que la desactivas. Mantén presionados los botones Atrás y Recientes al mismo tiempo para anular la fijación."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Esta función mantiene fija la vista de la pantalla hasta que la desactivas. Mantén presionado el botón Recientes para anular la fijación."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 5dfb878..d3cae62 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mostrar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ocultar"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fijada"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para ello, mantén pulsados los botones de retroceso e información general."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"La pantalla se mantendrá visible hasta que dejes de fijarla. Para ello, mantén pulsado el botón de información general."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index d3d5120..0dfbdfc 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laiendamine"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ahendamine"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekraan on kinnitatud"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"See hoiab selle kuval, kuni selle vabastate. Vabastamiseks puudutage ning hoidke korraga all nuppe Tagasi ja Ülevaade."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"See hoiab selle kuval, kuni selle vabastate. Vabastamiseks puudutage ja hoidke all nuppu Ülevaade."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selge"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tänan, ei"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kas lülitada Bluetooth sisse?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviatuuri ühendamiseks tahvelarvutiga peate esmalt Bluetoothi sisse lülitama."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Lülita sisse"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index d48373c..769164d 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zabaldu"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tolestu"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantaila ainguratuta dago"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Horrela, ikusgai mantenduko da aingura kendu arte. Aingura kentzeko, eduki ukituta aldi berean \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Horrela, ikusgai mantenduko da, aingura kendu arte. Aingura kentzeko, eduki ukituta \"Ikuspegi orokorra\" botoia."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ados"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ez, eskerrik asko"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Erakutsi distira Ezarpen bizkorretan"</string>
     <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f9e2b22..6d9d43f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -219,7 +219,7 @@
     <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
     <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
     <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
-    <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی وجود ندارد"</string>
+    <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی ندارید"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏جستجو برای GPS"</string>
     <string name="gps_notification_found_text" msgid="4619274244146446464">"‏مکان تنظیم شده توسط GPS"</string>
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"بزرگ کردن"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"کوچک کردن"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"صفحه نمایش پین شد"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، برگشت و نمای کلی را به صورت هم‌زمان لمس کنید و نگه‌دارید."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، نمای کلی را لمس کنید و نگه‌دارید."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
     <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
     <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوتوث روشن شود؟"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"برای مرتبط کردن صفحه‌کلید با رایانه لوحی، ابتدا باید بلوتوث را روشن کنید."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"روشن کردن"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7816337..79bf369 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laajenna."</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tiivistä."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Näyttö on kiinnitetty"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Tämä pitää sen näkyvissä, kunnes poistat kiinnityksen. Kosketa Edellinen- ja Viimeisimmät-kohtaa samanaikaisesti pitkään kiinnityksen poistamiseksi."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Tämä pitää sen näkyvissä, kunnes poistat kiinnityksen. Kosketa Viimeisimmät-kohtaa pitkään kiinnityksen poistamiseksi."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selvä"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ei kiitos"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
     <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 66c435c..605e4c5 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"L\'écran est épinglé"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez un doigt simultanément sur « Retour » et « Aperçu »."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Cet écran est épinglé jusqu\'à ce que vous annuliez l\'opération. Pour annuler l\'épinglage, maintenez le doigt sur « Aperçu »."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
     <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5b39201..6beed78 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -327,8 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
-    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
-    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Écran épinglé"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Cet écran est épinglé jusqu\'à annulation de l\'opération. Pour annuler l\'épinglage, appuyez simultanément sur \"Retour\" et \"Aperçu\" de manière prolongée."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Cet écran est épinglé jusqu\'à annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur \"Aperçu\"."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index e5329ed..9a66d87 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ampliar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A pantalla está fixada"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"A pantalla manterase visible ata que anules a fixación. Para facelo, mantén premido Atrás e Visión xeral ao mesmo tempo."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"A pantalla manterase visible ata que anules a fixación. Para facelo, mantén premido Visión xeral."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"De acordo"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, grazas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 38594be..fe60448 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"વિસ્તૃત કરો"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"સંકુચિત કરો"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"સ્ક્રીન પિન કરેલ છે"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યમાં રાખે છે. અનપિન કરવા માટે બેકને ટચ કરો અને પકડો અને તે જ સમયે વિહંગાવલોકન કરો."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યમાં રાખે છે. અનપિન કરવા માટે વિહંગાવલોકનને ટચ કરો અને પકડો."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
     <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ચાલુ કરવુ છે?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"તમારા ટેબ્લેટ સાથે કીબોર્ડ કનેક્ટ કરવા માટે, તમારે પહેલાં Bluetooth ચાલુ કરવાની જરૂર પડશે."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ચાલુ કરો"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 2abf37b..a433ca5 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करें"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त करें"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्‍क्रीन पिन कर दी गई है"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"इससे वह तब तक दृश्‍य में रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए वापस जाएं और अवलोकन करें को एक ही समय पर स्‍पर्श करके रखें."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"इससे वह तब तक दृश्‍य में बना रहता है जब तक कि आप उसे अनपिन नहीं कर देते. अनपिन करने के लिए अवलोकन करें को स्‍पर्श करके रखें."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
     <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटूथ चालू करें?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"अपने कीबोर्ड को अपने टैबलेट से कनेक्ट करने के लिए, आपको पहले ब्लूटूथ चालू करना होगा."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 30f22b7..b72ac3d 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -394,8 +394,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširivanje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sažimanje"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je prikvačen"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Istovremeno dodirnite i držite Natrag i Pregled da biste ga otkvačili."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i držite Pregled da biste ga otkvačili."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Shvaćam"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -441,10 +441,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li uključiti Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tipkovnicu s tabletom, morate uključiti Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index e1a57f9..d27813a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kibontás"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Összecsukás"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A képernyő rögzítve van"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Megjelenítve tartja addig, amíg Ön fel nem oldja fel a rögzítést. A rögzítés feloldásához tartsa egyszerre lenyomva a Vissza és az Áttekintés lehetőséget."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Értem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nem, köszönöm"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
     <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Engedélyezi a Bluetooth-kapcsolatot?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ha a billentyűzetet csatlakoztatni szeretné táblagépéhez, először engedélyeznie kell a Bluetooth-kapcsolatot."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bekapcsolás"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 6124ef2..125b19d 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ընդարձակել"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Կոծկել"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար միաժամանակ հպեք և պահեք Համատեսքի և Հետ կոճակները:"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսքի կոճակը:"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
     <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2ce7a5b..1370ef4 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Luaskan"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ciutkan"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Layar dipasangi pin"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh dan tahan tombol Kembali dan Ringkasan secara bersamaan untuk melepas pin."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ini akan terus ditampilkan sampai Anda melepas pin. Sentuh dan tahan tombol Ringkasan untuk melepas pin."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Mengerti"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Lain kali"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index cb95cde..a57e66c 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Stækka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minnka"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjárinn er festur"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Þetta heldur þessu opnu þangað til þú losar. Haltu bakk- og yfirlitshnöppunum inni á sama tíma til að losa."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Þetta heldur þessu opnu þangað til þú losar. Haltu yfirlitshnappinum inni til að losa."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ég skil"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
     <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 1e0cec7..77be017 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è bloccata"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"La schermata rimane visibile finché la sblocchi. Tocca e tieni premuti contemporaneamente Indietro e Panoramica per sbloccare."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"La schermata rimane visibile finché la sblocchi. Tocca Panoramica e tieni premuto per sbloccare."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 88c6fbd..20cb1ea 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"הרחב"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"שומר בתצוגה עד לביטול ההצמדה. גע והחזק בו-זמנית ב\'הקודם\' ו\'סקירה\' כדי לבטל הצמדה."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"שומר בתצוגה עד לביטול ההצמדה. גע והחזק בו-זמנית ב\'הקודם\' ו\'סקירה\' כדי לבטל הצמדה."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"סידור מחדש של הגדרות מהירות"</string>
     <string name="show_brightness" msgid="6613930842805942519">"הצג בהירות בהגדרות מהירות"</string>
     <string name="experimental" msgid="6198182315536726162">"ניסיוניות"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 6006f64..3d40c73 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"折りたたむ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"画面が固定されました"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"固定を解除するまで画面が常に表示されるようになります。[戻る]と[最近]を同時に押し続けると固定が解除されます。"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"固定を解除するまで画面が常に表示されるようになります。[最近]を押し続けると固定が解除されます。"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
     <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
     <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index f74a434..8f42d5b 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"გავრცობა"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ჩაკეცვა"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ეკრანი ჩამაგრებულია"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ამით ის ხედში დარჩება, სანამ ჩამაგრებას არ გააუქმებთ. ჩამაგრების გასაუქმებლად შეეხეთ და დააყოვნეთ „დაბრუნება“-ზე და „მიმოხილვა“-ზე ერთდროულად."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ამით ის ხედში დარჩება, სანამ ჩამაგრებას არ გააუქმებთ. ჩამაგრების გასაუქმებლად შეეხეთ და დააყოვნეთ „მიმოხილვა“-ზე."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
     <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
     <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 4483303..192518a 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жаю"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жию"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран түйрелді"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Бұл сіз оны босатқанша оны көрсетіп тұрады. Босату үшін «Кері» және «Шолу» түймелерін бір уақытта басып тұрыңыз."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Бұл сіз оны босатқанша оны көрсетіп тұрады. Босату үшін «Шолу» түймесін бір уақытта басып тұрыңыз."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
     <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 9b17ffc..284af53 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ពង្រីក"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"បង្រួម"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"អេក្រង់​ត្រូវ​បាន​ភ្ជាប់"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"រក្សាទុក​វា​ក្នុង​ទិដ្ឋភាព​រហូត​ដល់​អ្នក​ផ្ដាច់។ ប៉ះ ហើយ​សង្កត់​ថយក្រោយ និង​ទិដ្ឋភាព​នៅ​ពេល​តែ​មួយ​ដើម្បី​ផ្ដាច់។"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"វា​រក្សាទុក​ក្នុង​ទិដ្ឋភាព​រហូត​ដល់​អ្នក​ផ្ដាច់។ ប៉ះ និង​សង្កត់​ទិដ្ឋភាព​ដើម្បី​ផ្ដាច់។"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
     <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"បើកប៊្លូធូសឬ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ដើម្បីភ្ជាប់ក្តារចុចរបស់អ្នកជាមួយនឹងថេប្លេតរបស់អ្នក អ្នកត្រូវតែបើកប៊្លូធូសជាមុនសិន។"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"បើក"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 7401340..484551b 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ವಿಸ್ತರಿಸು"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ಸಂಕುಚಿಸು"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ಪರದೆಯನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಒಂದೇ ಸಮಯದಲ್ಲಿ ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಒತ್ತಿ ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅವಲೋಕಿಸಿ."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
     <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ನಿಮ್ಮ ಕೀಬೋರ್ಡ್ ಅನ್ನು ಟ್ಯಾಬ್ಲೆಟ್‌ಗೆ ಸಂಪರ್ಕಿಸಲು, ನೀವು ಮೊದಲು ಬ್ಲೂಟೂತ್ ಆನ್ ಮಾಡಬೇಕಾಗುತ್ತದೆ."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ಆನ್ ಮಾಡು"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1f7fec7..c7f5489 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"펼치기"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"접기"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 뒤로와 최근 사용을 동시에 길게 터치합니다."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"고정 해제하기 전까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치합니다."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
     <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
     <string name="experimental" msgid="6198182315536726162">"베타"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"블루투스를 켜시겠습니까?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"키보드를 태블릿에 연결하려면 먼저 블루투스를 켜야 합니다."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"사용"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 00ce218..f57c9fc 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жайып көрсөтүү"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жыйнап коюу"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран кадалган"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Бул бошотулмайынча көрүнө берет. Бошотуу үчүн, бир убакта Артка жана Карап чыгууну коё бербей басып туруңуз."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Бул бошотулмайынча көрүнө берет. Бошотуу үчүн, Карап чыгууну коё бербей басып туруңуз."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарык деңгээлин көрсөтүү"</string>
     <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 92dbb4d..18f3111 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ຂະຫຍາຍ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ຫຍໍ້ລົງ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກ​ໝຸດໜ້າ​ຈໍ​ແລ້ວ"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ມັນ​ຈະ​ຮັກ​ສາ​ໜ້າ​ຈໍ​ໄວ້​ໃນ​ມຸມມອງ​ຂອງ​ທ່ານ​ຈົນ​ກວ່າ​ທ່ານ​ຈະ​ຖອດ​ໝຸດ. ​ແຕະ​ປຸ່ມ ກັບ​ຄືນ ແລະ ພາບ​ຮວມ​ ຄ້າງ​ໄວ້​ພ້ອມ​ກັນ​ເພື່ອ​ຖອດ​ໝຸດ."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ມັນ​ຈະ​ຮັກ​ສາ​ໜ້າ​ຈໍ​ໄວ້​ໃນ​ມຸມມອງ​ຂອງ​ທ່ານ​ຈົນ​ກວ່າ​ທ່ານ​ຈະ​ຖອດ​ໝຸດ. ​ແຕະ​ປຸ່ມ ພາບ​ຮວມ​ ຄ້າງ​ໄວ້​ເພື່ອ​ຖອດ​ໝຸດ."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
     <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ເປີດ​ໃຊ້ Bluetooth ບໍ່?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ເພື່ອ​ເຊື່ອມ​ຕໍ່​ແປ້ນ​ພິມ​ຂອງ​ທ່ານ​ກັບ​ແທັບ​ເລັດ​ຂອງ​ທ່ານ, ກ່ອນ​ອື່ນ​ໝົດ​ທ່ານ​ຕ້ອງ​ເປີດ Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ເປີດ​"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 304afe4..307b7d9 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Išskleisti"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sutraukti"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekranas prisegtas"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Tai bus rodoma, kol atsegsite. Kad atsegtumėte, tuo pačiu metu palieskite ir laikykite „Atgal“ ir „Apžvalga“."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Tai bus rodoma, kol atsegsite. Kad atsegtumėte, palieskite ir laikykite „Apžvalga“."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Supratau"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, ačiū"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index a1a437d..3660cda 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -394,8 +394,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Izvērst"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sakļaut"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrāns ir piesprausts"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, vienlaikus pieskarieties vienumiem “Atpakaļ” un “Pārskats” un turiet tos nospiestus."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties vienumam “Pārskats” un turiet to nospiestu."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Sapratu!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nē, paldies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -441,10 +441,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 808943b..f8d0417 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Собери"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранот е прикачен"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ќе се гледа сè додека не го откачите. Допрете и држете Назад и Краток преглед истовремено за откачување."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ќе се гледа сè додека не го откачите. Допрете и држете Краток преглед за откачување."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се вклучи Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да ја поврзете тастатурата со таблетот, најпрво треба да вклучите Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Вклучи"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 7724f34..516e846 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"സ്‌ക്രീൻ പിൻ ചെയ്‌തു"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തുന്നു. അൺപിൻ ചെയ്യാൻ \'മടങ്ങുക\', \'ചുരുക്കവിവരണം\' എന്നിവ ഒരേ സമയം സ്‌പർശിച്ച് പിടിക്കുക."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തുന്നു. അൺപിൻ ചെയ്യുന്നതിന് \'ചുരുക്കവിവരണം\' സ്‌പർശിച്ചുപിടിക്കുക."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
     <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ഓണാക്കണോ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"നിങ്ങളുടെ ടാബ്‌ലെറ്റുമായി കീബോർഡ് കണക്റ്റുചെയ്യുന്നതിന്, ആദ്യം Bluetooth ഓണാക്കേണ്ടതുണ്ട്."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ഓണാക്കുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index cecf5af..8cb8df1 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -391,8 +391,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Дэлгэх"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Хураах"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Дэлгэц эхэнд байрлуулагдсан"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Таныг эхэнд нээхийг болиулах хүртэл харагдана. Хүрээд, Back дээр удаан дараад хаахдаа Overview-ийг дар"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Таныг эхэнд нээхийг болиулах хүртэл харагдана. Хаахын тулд хүрээдOverview-ийг дар"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -438,10 +438,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
     <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index b253849..cfa6b5f 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करा"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संकुचित करा"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन केलेली आहे"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"हे आपण अनपिन करेपर्यंत दृश्यामध्ये ते ठेवते. अनपिन करण्यासाठी एकाच वेळी परत आणि अलीकडील ला स्पर्श करा आणि धरून ठेवा आणि विहंगावलोकन करा."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"हे आपण अनपिन करेपर्यंत दृश्यामध्ये ते ठेवते. अनपिन करण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिंग्जची पुनर्रचना करा"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5a94581..6ff9a61 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kembangkan"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Runtuhkan"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrin telah disemat"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ini akan memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh dan tahan Kembali dan Gambaran Keseluruhan pada masa yang sama untuk menyahsemat."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ini akan memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh dan tahan Gambaran Keseluruhan untuk menyahsemat."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Faham"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tidak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
     <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 855df4d..e4b3e54 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"တိုးချဲ့ရန်"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ခေါက်သိမ်းရန်..."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"မျက်နှာပြင် ပင်ထိုးပြီးပါပြီ"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"သင်ပင်ဖြုတ်သည့် တိုင်အောင် ၎င်းအား မြင်ကွင်းတွင် ထားရှိပါမည်။ ပင်ဖြုတ်ရန် အနောက်နှင့် ခြုံငုံကြည့်ခြင်းကို ဖိ၍ နှိပ်ထားနိုင်သည်။"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"သင်ပင်ဖြုတ်သည့် တိုင်အောင် ၎င်းအား မြင်ကွင်းတွင် ထားရှိပါမည်။ ပင်ဖြုတ်ရန် ခြုံငုံကြည့်ခြင်းကို ဖိ၍ နှိပ်ထားနိုင်သည်။"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
     <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
     <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ဘလူးတုသ် ဖွင့်ရမလား။"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ကီးဘုတ်ကို တပ်ဘလက်နှင့် ချိတ်ဆက်ရန်၊ ပမထဦးစွာ ဘလူးတုသ်ကို ဖွင့်ပါ။"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ဖွင့်ပါ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index d662464..2882d7a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk på og hold inne Tilbake og Oversikt samtidig for å låse opp."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"På denne måten blir skjermen synlig frem til du låser den opp. Trykk på og hold inne Tilbake og Oversikt for å låse opp."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
     <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 8333fb0..19d84ce 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -380,7 +380,7 @@
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"तपाईँ <xliff:g id="APPLICATION">%1$s</xliff:g> सँग जडित हुनुहुन्छ जसले इ-मेल, अनुप्रयोगहरू र वेबसाइट लगायतका तपाईँको निजी नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।"</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि, आफ्नो प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"तपाईँको कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थापन गरिन्छ। यो <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> सँग जोडिएको छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधि अनुगमन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> सँग पनि जडित हुनुहुन्छ, जसले तपाईँको व्यक्तिगत नेटवर्क गतिविधि अनुगमन गर्न सक्छ।"</string>
-    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"तपाईंको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थित गरिन्छ।\n\nतपाईंको प्रशासकले तपाईँको यन्त्र र त्यसको स्थान जानकारीमार्फत सेटिङहरू,  कर्पोरेट पहुँच, अनुप्रयोगहरू, तपाईँको यन्त्रसँग सम्बद्ध डेटा  र तपाईँको यन्त्रको स्थान जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।\n\nतपाईं <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जडित हुनुहुन्छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि तपाईको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"तपाईँको उपकरण <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारा व्यवस्थित गरिन्छ।\n\nतपाईँको प्रशासकले तपाईँको यन्त्र र त्यसको स्थान जानकारीमार्फत सेटिङहरू,  कर्पोरेट पहुँच, अनुप्रयोगहरू, तपाईँको यन्त्रसँग सम्बद्ध डेटा  र तपाईँको यन्त्रको स्थान जानकारीको अनुगमन र व्यवस्थापन गर्न सक्छ।\n\nतपाईँ <xliff:g id="APPLICATION">%2$s</xliff:g> सँग जडित हुनुहुन्छ जसले इमेल, अनुप्रयोगहरू, र वेबसाइटहरू लगायतका तपाईँका नेटवर्क गतिविधिका अनुगमन गर्न सक्छ।\n\nथप जानकारीको लागि तपाईको प्रशासकलाई सम्पर्क गर्नुहोस्।"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"तपाईँले नखोले सम्म उपकरण बन्द रहनेछ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"छिटो सूचनाहरू प्राप्त गर्नुहोस्"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"तपाईँले अनलक गर्नअघि तिनीहरूलाई हेर्नुहोस्"</string>
@@ -393,12 +393,12 @@
     <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="1346522416878235405">"तपाईं अनपिन सम्म यो दृश्य मा राख्छ। छुनुहोस् र अनपिन फिर्ता र सिंहावलोकन नै समय मा पकड।"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"तपाईं अनपिन सम्म यो दृश्य मा राख्छ। छुनुहोस् र अनपिन गर्न सिंहावलोकन पकड।"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
-    <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"यो तपाईं सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
+    <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"यो तपाईँ सेटिङ् मा यो बारी अर्को समय देखापर्नेछ।"</string>
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
     <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
     <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लुटुथ सक्रिय पार्ने हो?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"आफ्नो ट्याब्लेटसँग किबोर्ड जोड्न, पहिले तपाईँले ब्लुटुथ सक्रिय गर्नुपर्छ।"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"सक्रिय पार्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3bca7c4..95ddeab 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Uitvouwen"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Samenvouwen"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Scherm is vastgezet"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Het scherm blijft zichtbaar totdat u het u losmaakt. Houd \'Terug\' en \'Overzicht\' tegelijkertijd aangeraakt om het los te maken."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Het scherm blijft zichtbaar totdat u het u losmaakt. Houd \'Overzicht\' aangeraakt om het los te maken."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ik snap het"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, bedankt"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth inschakelen?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Als je je toetsenbord wilt verbinden met je tablet, moet je eerst Bluetooth inschakelen."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Inschakelen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index d431999..6cb50b3 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ਨਸ਼ਟ ਕਰੋ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ਇਹ ਇਸਨੂੰ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿਨ ਕਰਨ ਲਈ ਪਿੱਛੇ ਅਤੇ ਰੂਪ-ਰੇਖਾ ਨੂੰ ਇੱਕੋ ਸਮੇਂ ਛੋਹਵੋ ਅਤੇ ਹੋਲਡ ਕਰੋ।"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ਇਹ ਇਸਨੂੰ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿਨ ਕਰਨ ਲਈ ਰੂਪ-ਰੇਖਾ ਨੂੰ ਛੋਹਵੋ ਅਤੇ ਹੋਲਡ ਕਰੋ।"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
     <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth ਚਾਲੂ ਕਰੋ?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ਆਪਣੇ ਟੈਬਲੇਟ ਨਾਲ ਆਪਣਾ ਕੀ-ਬੋਰਡ ਕਨੈਕਟ ਕਰਨ ਲਈ, ਤੁਹਾਨੂੰ ਪਹਿਲਾਂ Bluetooth ਚਾਲੂ ਕਰਨ ਦੀ ਜ਼ਰੂਰਤ ਹੈ।"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ਚਾਲੂ ਕਰੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index e1a57be..1821cdd 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozwiń"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zwiń"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran jest przypięty"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj jednocześnie Wstecz i Przegląd."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, dziękuję"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index e94318b..68ecfc8 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ela é mantida à vista até que seja liberada. Toque em \"Voltar\" e \"Visão Geral\" e mantenha essas opções pressionadas ao mesmo tempo para liberar."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ela é mantida à vista até que seja liberada. Toque em \"Visão geral\" e mantenha essa opção pressionada para liberar."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index a41ee93..61a76f9 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Reduzir"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"O ecrã está fixado"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Será mantido na vista até soltar. Toque sem soltar em Anterior e Vista geral em simultâneo para soltar."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Será mantido na vista até soltar. Toque sem soltar em Vista geral para soltar."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Compreendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar as Definições rápidas"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index e94318b..68ecfc8 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ela é mantida à vista até que seja liberada. Toque em \"Voltar\" e \"Visão Geral\" e mantenha essas opções pressionadas ao mesmo tempo para liberar."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ela é mantida à vista até que seja liberada. Toque em \"Visão geral\" e mantenha essa opção pressionada para liberar."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
     <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 64560b9..3af273d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -255,7 +255,7 @@
     <string name="quick_settings_location_off_label" msgid="7464544086507331459">"Localizarea este dezactivată"</string>
     <string name="quick_settings_media_device_label" msgid="1302906836372603762">"Dispozitiv media"</string>
     <string name="quick_settings_rssi_label" msgid="7725671335550695589">"RSSI"</string>
-    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Numai apeluri de urgenţă"</string>
+    <string name="quick_settings_rssi_emergency_only" msgid="2713774041672886750">"Numai apeluri de urgență"</string>
     <string name="quick_settings_settings_label" msgid="5326556592578065401">"Setări"</string>
     <string name="quick_settings_time_label" msgid="4635969182239736408">"Ora"</string>
     <string name="quick_settings_user_label" msgid="5238995632130897840">"Eu"</string>
@@ -394,8 +394,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Extindeți"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Restrângeți"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ecranul este fixat"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ecranul este afișat până anulați fixarea. Apăsați lung pe Înapoi și pe Vizualizare generală simultan pentru a anula fixarea."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ecranul este afișat până anulați fixarea. Apăsați lung pe Vizualizare generală pentru a anula fixarea."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Am înțeles"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nu, mulțumesc"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -441,10 +441,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 7487393..296876c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -397,8 +397,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Развернуть"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свернуть"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Блокировка в приложении включена"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Это приложение останется активным, пока вы не отмените блокировку, одновременно нажав кнопки \"Назад\" и \"Обзор\"."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Приложение останется активным, пока вы не отмените блокировку, одновременно нажав кнопки Назад и Обзор."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -444,10 +444,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
     <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index c54f0ff..185fc05 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -393,8 +393,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="1346522416878235405">"ඔබ ගලවන තෙක් එය දර්ශනය තුළ මෙය තබයි. ගැලවීමට ආපසු සහ දළ විශ්ලේෂණය එකම වේලාවක ස්පර්ෂ කර අල්ලා සිටින්න."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ඔබ ගලවන තෙක් එය දර්ශනය තුළ මෙය තබයි. ගැලවීමට දළ විශ්ලේෂණය ස්පර්ෂ කර අල්ලා සිටින්න."</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>
@@ -440,10 +439,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
     <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
     <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"බ්ලූටූත් ක්‍රියාත්මක කරන්නද?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"ඔබේ යතුරු පුවරුව ඔබේ ටැබ්ලට් පරිගණකයට සම්බන්ධ කිරීමට, ඔබ පළමුව බ්ලූටූත් ක්‍රියාත්මක කළ යුතුය."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ක්‍රියාත්මක කරන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index adde8be..ebfd035 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -397,8 +397,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbaliť"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zbaliť"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je pripnutá"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Ak ho chcete uvoľniť, stlačte a podržte súčasne tlačidlá Späť a Prehľad."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Dobre"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, vďaka"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -444,10 +444,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2542807..d87b9a4 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Razširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Strni"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je pripet"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"S tem ostane zaslon v pogledu, dokler ga ne odpnete. Hkrati pridržite tipko za nazaj in tipko za pregled, če ga želite odpeti."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"S tem ostane zaslon v pogledu, dokler ga ne odpnete. Pridržite tipko za pregled, če ga želite odpeti."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Razumem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
     <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite vklopiti Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Če želite povezati tipkovnico in tablični računalnik, vklopite Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vklop"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index a710477..5519e6b 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zgjeroje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Mbylle"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrani u gozhdua"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Kjo e ruan në pamje derisa e heq nga gozhdimi. Prek dhe mbaj shtypur njëkohësisht \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Kjo e ruan në pamje derisa e heq nga gozhdimi. Prek dhe mbaj shtypur njëkohësisht \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Të fshihet <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
     <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Të aktivizohet \"bluetooth-i\"?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Për të lidhur tastierën me tabletin, në fillim duhet të aktivizosh \"bluetooth-in\"."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivizo"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index c171a60..67959f5 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -394,8 +394,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Скупи"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран је закачен"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"На овај начин ово остаје приказано док га не откачите. Истовремено додирните и задржите Назад и Преглед да бисте га откачили."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"На овај начин ово остаје приказано док га не откачите. Додирните и задржите Преглед да бисте га откачили."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -441,10 +441,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index fae5ab9..48fe512 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -314,9 +314,9 @@
     <string name="speed_bump_explanation" msgid="1288875699658819755">"Mindre brådskande aviseringar nedan"</string>
     <string name="notification_tap_again" msgid="8524949573675922138">"Tryck igen för att öppna"</string>
     <string name="keyguard_unlock" msgid="8043466894212841998">"Svep uppåt om du vill låsa upp"</string>
-    <string name="phone_hint" msgid="4872890986869209950">"Dra från ikonen och öppna telefonen"</string>
-    <string name="voice_hint" msgid="8939888732119726665">"Dra från ikonen och öppna röstassistenten"</string>
-    <string name="camera_hint" msgid="7939688436797157483">"Dra från ikonen och öppna kameran"</string>
+    <string name="phone_hint" msgid="4872890986869209950">"Svep från ikonen och öppna telefonen"</string>
+    <string name="voice_hint" msgid="8939888732119726665">"Svep från ikonen och öppna röstassistenten"</string>
+    <string name="camera_hint" msgid="7939688436797157483">"Svep från ikonen och öppna kameran"</string>
     <string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Total tystnad. Även skärmläsningsprogram tystas."</string>
     <string name="interruption_level_none" msgid="6000083681244492992">"Helt tyst"</string>
     <string name="interruption_level_priority" msgid="6426766465363855505">"Bara prioriterade"</string>
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Med den här funktionen är skärmen synlig tills du lossar den. Tryck länge på Tillbaka och Översikt samtidigt om du vill lossa skärmen."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Detta visar skärmen tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
     <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 5b46a7e..2b65540 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Panua"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Kunja"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrini imebandikwa"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Hii itaendelea kuonyesha hadi ubandue. Gusa na ushikilie Nyuma na Muhtasari kwa wakati mmoja ili ubandue."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Hii itaendelea kuonyesha hadi uibandue. Gusa na ushikilie Muhtasari ili ubandue."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Nimeelewa"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hapana, asante"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
     <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Je, ungependa kuwasha Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ili uunganishe Kibodi yako kwenye kompyuta yako kibao, lazima kwanza uwashe Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Washa"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 477b715..1f4a4a2 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"விரிவாக்கு"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"சுருக்கு"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"திரை பொருத்தப்பட்டது"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"பொருத்தியதை விலக்கும்வரை இதைக் காட்சியில் வைக்கும். விலக்க, பின் மற்றும் மேலோட்டப் பார்வையை ஒரே நேரத்தில் தொட்டுப் பிடிக்கவும்."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"பொருத்தியதை விலக்கும்வரை இதைக் காட்சியில் வைக்கும். விலக்க, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
     <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
     <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"புளூடூத்தை இயக்கவா?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"உங்கள் டேப்லெட்டுடன் விசைப்பலகையை இணைக்க, முதலில் புளூடூத்தை இயக்க வேண்டும்."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"இயக்கு"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index f718669a..d0b3439 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"ఇది మీరు అన్‌పిన్ చేసే వరకు దీన్ని వీక్షణలో ఉంచుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టిని ఒకేసారి తాకి, ఉంచండి."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"ఇది మీరు అన్‌పిన్ చేసే వరకు దీన్ని వీక్షణలో ఉంచుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి, ఉంచండి."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
     <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
     <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"బ్లూటూత్ ఆన్ చేయాలా?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"మీ కీబోర్డ్‌ను మీ టాబ్లెట్‌తో కనెక్ట్ చేయడానికి, మీరు ముందుగా బ్లూటూత్ ఆన్ చేయాలి."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ఆన్ చేయి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index ca4000a..cb2921d 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ขยาย"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ยุบ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ตรึงหน้าจอแล้ว"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"การดำเนินการนี้จะเปิดหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"กลับ\" และ \"ภาพรวม\" พร้อมกันค้างไว้เพื่อเลิกตรึง"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"การดำเนินการนี้จะเปิดหน้าจอนี้ไว้เสมอจนกว่าคุณจะเลิกตรึง แตะ \"ภาพรวม\" ค้างไว้เพื่อเลิกตรึง"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
     <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
     <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 5e8bb7a..43969e9 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Palawakin"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"I-collapse"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Naka-pin ang screen"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Pinapanatili nitong nasa view ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Bumalik at Pangkalahatang-ideya nang sabay upang mag-unpin."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Pinapanatili nitong nasa view ito hanggang sa mag-unpin ka. Pindutin nang matagal ang Pangkalahatang-ideya upang mag-unpin."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Nakuha ko"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hindi, salamat na lang"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Itago ang <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
     <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index dbca4c7..7a044ef 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişlet"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Daralt"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran sabitlendi"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Böylece siz sabitlemesini kaldırana kadar görüntülenmeye devam eder. Sabitlemeyi kaldırmak için Geri ve Genel Bakış öğesine aynı anda dokunun ve basılı tutun."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Böylece siz sabitlemesini kaldırana kadar görüntülenmeye devam eder. Sabitlemeyi kaldırmak için Genel Bakış\'a dokunun ve basılı tutun."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hayır, teşekkürler"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
     <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 8f8793c..37030ac 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Розгорнути"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згорнути"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран закріплено"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Закріпить екран, щоб ви могли постійно його бачити, доки не відкріпите. Щоб відкріпити, одночасно натисніть і втримуйте кнопки \"Назад\" і \"Огляд\"."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Закріпить екран, щоб ви могли постійно його бачити, доки не відкріпите. Щоб відкріпити, натисніть і втримуйте кнопку \"Огляд\"."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
     <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 086f9e2..0712f98 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"پھیلائیں"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"سکیڑیں"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"اسکرین پن کردہ ہے"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"یہ اس کو اس وقت تک منظر میں رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے واپس اور عمومی جائزہ کو ایک ساتھ ٹچ کریں اور پکڑ کر رکھیں۔"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"یہ اس کو اس وقت تک منظر میں رکھتا ہے جب تک آپ اس سے پن نہیں ہٹا دیتے۔ پن ہٹانے کیلئے عمومی جائزہ کو ٹچ کریں اور پکڑ کر رکھیں۔"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
     <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
     <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index b1a556a..ad3dcc7 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Ekran yechilmaguncha u qadalgan holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy nazar” tugmalarini bir vaqtda bosing va ushlab turing."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Ekran yechilmaguncha u qadalgan holatda qoladi. Uni yechish uchun “Umumiy nazar” tugmasini bosing va ushlab turing."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
     <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index e22909c..f13033b 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mở rộng"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Thu gọn"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Màn hình được ghim"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Chạm và giữ nút Quay lại và Tổng quan cùng một lúc để bỏ ghim."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Chạm và giữ nút Quay lại để bỏ ghim."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ok"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Không, cảm ơn"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
     <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bật Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Để kết nối bàn phím với máy tính bảng, trước tiên, bạn phải bật Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Bật"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 9d32567..ade7636 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展开"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收起"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"已固定屏幕"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"这将会固定显示此屏幕,直到您取消固定为止。触摸并同时按住“返回”和“概览”即可取消固定屏幕。"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"这将会固定显示此屏幕,直到您取消固定为止。触摸并按住“概览”即可取消固定屏幕。"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速设置"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速设置中显示亮度栏"</string>
     <string name="experimental" msgid="6198182315536726162">"实验性"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d80eb72..aa6e065c 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"在您取消固定前,它會保持在檢視狀態。輕觸並同時按住 [返回] 和 [概覽],即可取消固定。"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"在您取消固定前,它會保持在檢視狀態。輕觸並按住 [概覽] 即可取消固定。"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index e7a4450..ffaaefe 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -395,8 +395,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。同時按住返回按鈕和總覽按鈕即可取消固定。"</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住總覽按鈕即可取消固定。"</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <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>
@@ -442,10 +442,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
     <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
     <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 06dc0c9..f1df714 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -393,8 +393,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Nweba"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Goqa"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Isikrini siphiniwe"</string>
-    <string name="screen_pinning_description" msgid="1346522416878235405">"Lokhu kukugcina kubukeka uze ususe ukuphina. Thinta futhi ubambe u-Emuva no-Ukubuka konke ngesikhathi esisodwa ukuze ususe ukuphina."</string>
-    <string name="screen_pinning_description_accessible" msgid="8518446209564202557">"Lokhu kukugcina kubukeka uze ususe ukuphina. Thinta futhi ubambe u-Ukubuka konke ukuze ususe ukuphina."</string>
+    <!-- no translation found for screen_pinning_description (3577937698406151604) -->
+    <skip />
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ngiyitholile"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Cha ngiyabonga"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -440,10 +440,7 @@
     <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
     <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
     <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
-    <!-- no translation found for enable_bluetooth_title (5027037706500635269) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_message (9106595990708985385) -->
-    <skip />
-    <!-- no translation found for enable_bluetooth_confirmation_ok (6258074250948309715) -->
-    <skip />
+    <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
+    <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
+    <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index bae8017..0c638a2 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -136,7 +136,7 @@
     <integer name="touch_acceptance_delay">700</integer>
 
     <!-- The duration in seconds to wait before the dismiss buttons are shown. -->
-    <integer name="recents_task_bar_dismiss_delay_seconds">1</integer>
+    <integer name="recents_task_bar_dismiss_delay_seconds">1000</integer>
 
     <!-- The min animation duration for animating views that are currently visible. -->
     <integer name="recents_filter_animate_current_views_duration">250</integer>
@@ -269,9 +269,6 @@
     <!-- Duration of the expansion animation in the volume dialog -->
     <item name="volume_expand_animation_duration" type="integer">300</item>
 
-    <!-- Whether to show a "shelf" of apps at the bottom of the screen. -->
-    <bool name="config_enableAppShelf">false</bool>
-
     <!-- Whether to show the full screen user switcher. -->
     <bool name="config_enableFullscreenUserSwitcher">false</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cbc92f2..c413524 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -36,6 +36,18 @@
     <!-- The font size for the clock -->
     <dimen name="status_bar_clock_size">14sp</dimen>
 
+    <!-- The margin on the start of the content view -->
+    <dimen name="notification_content_margin_start">16dp</dimen>
+
+    <!-- The maximum size of the title when in single line mode -->
+    <dimen name="notification_maximum_title_length">150sp</dimen>
+
+    <!-- The margin on the end of the content view -->
+    <dimen name="notification_content_margin_end">8dp</dimen>
+
+    <!-- Height of a single line notification in the status bar -->
+    <dimen name="notification_single_line_height">32sp</dimen>
+
     <!-- Height of a small notification in the status bar -->
     <dimen name="notification_min_height">64dp</dimen>
 
@@ -128,6 +140,8 @@
     <dimen name="qs_new_tile_height">100dp</dimen>
     <dimen name="qs_quick_actions_height">88dp</dimen>
     <dimen name="qs_quick_actions_padding">25dp</dimen>
+    <dimen name="qs_quick_tile_size">48dp</dimen>
+    <dimen name="qs_quick_tile_padding">12dp</dimen>
     <dimen name="qs_page_indicator_size">12dp</dimen>
     <dimen name="qs_tile_icon_size">24dp</dimen>
     <dimen name="qs_tile_text_size">12sp</dimen>
@@ -230,6 +244,9 @@
     <!-- The size of the lock-to-app button icon. -->
     <dimen name="recents_lock_to_app_icon_size">28dp</dimen>
 
+    <!-- The amount to allow the stack to overscroll. -->
+    <dimen name="recents_stack_overscroll">24dp</dimen>
+
     <!-- Space reserved for the cards behind the top card in the top stack -->
     <dimen name="top_stack_peek_amount">12dp</dimen>
 
@@ -328,8 +345,8 @@
     <!-- radius of the corners of the material rounded rect background but negative-->
     <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen>
 
-    <!-- height of the bottom decor below the notification if present (eg. an expand action) -->
-    <dimen name="notification_bottom_decor_height">48dp</dimen>
+    <!-- height of notification header view if present -->
+    <dimen name="notification_header_height">32dp</dimen>
 
     <!-- The padding between notification children -->
     <dimen name="notification_children_padding">2dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3a5680d..d5f9557e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -751,6 +751,9 @@
     <!-- Text for overflow card on Keyguard when there is not enough space for all notifications on Keyguard. [CHAR LIMIT=1] -->
     <string name="keyguard_more_overflow_text">+<xliff:g id="number_of_notifications" example="5">%d</xliff:g></string>
 
+    <!-- The divider symbol between different parts of the notification header. not translatable [CHAR LIMIT=1] -->
+    <string name="notification_header_divider_symbol" translatable="false">•</string>
+
     <!-- An explanation for the visual speed bump in the notifications, which will appear when you click on it. [CHAR LIMIT=50] -->
     <string name="speed_bump_explanation">Less urgent notifications below</string>
 
@@ -978,12 +981,6 @@
     <!-- continue action for notification educating the user about enabling notifications on the lockscreen. [CHAR LIMIT=20] -->
     <string name="hidden_notifications_setup">Set up</string>
 
-    <!-- Text for the button to expand the notifications to show notification children [CHAR LIMIT=20] -->
-    <string name="notification_expand_button_text">See all</string>
-
-    <!-- Text for the button to expand the notifications to hide notification children [CHAR LIMIT=20] -->
-    <string name="notification_collapse_button_text">Hide all</string>
-
     <!-- Accessibility string for current zen mode and selected exit condition. A template that simply concatenates existing mode string and the current condition description. [CHAR LIMIT=20] -->
     <string name="zen_mode_and_condition"><xliff:g id="zen_mode" example="Priority interruptions only">%1$s</xliff:g>. <xliff:g id="exit_condition" example="For one hour">%2$s</xliff:g></string>
 
@@ -999,9 +996,7 @@
     <!-- Screen pinning dialog title. -->
     <string name="screen_pinning_title">Screen is pinned</string>
     <!-- Screen pinning dialog description. -->
-    <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back and Overview at the same time to unpin.</string>
-    <!-- Screen pinning dialog description when in accessibility mode. -->
-    <string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch and hold Overview to unpin.</string>
+    <string name="screen_pinning_description">This keeps it in view until you unpin. Touch and hold Back to unpin.</string>
     <!-- Screen pinning positive response. -->
     <string name="screen_pinning_positive">Got it</string>
     <!-- Screen pinning negative response. -->
@@ -1031,6 +1026,9 @@
     <!-- VolumeUI restoration notification: text -->
     <string name="volumeui_notification_text">Touch to restore the original.</string>
 
+    <!-- Describes the way 2 names are concatenated. An example would be ", " to produce "Peter Muller, Paul Curry". Please also include a space here if it's appropriate in the language and if it's a RTL language include it on the left. [CHAR LIMIT=3] -->
+    <string name="group_summary_concadenation">, </string>
+
     <!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
     <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 8f634e1..9e942f0 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -36,7 +36,6 @@
     <style name="RecentsTheme.Wallpaper">
         <!-- Wallpaper -->
         <item name="android:windowBackground">@color/transparent</item>
-        <item name="android:windowResizingBackground">@color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
     </style>
@@ -245,6 +244,10 @@
         <item name="android:textColor">#60000000</item>
     </style>
 
+    <style name="TextAppearance.Material.Notification.HeaderTitle"
+        parent="@*android:style/TextAppearance.Material.Notification.Info">
+    </style>
+
     <style name="SearchPanelCircle">
         <item name="android:layout_width">match_parent</item>
         <item name="android:layout_height">match_parent</item>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 1dca149..d9f7a46 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -21,8 +21,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
-import android.media.AudioAttributes;
-import android.os.Vibrator;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
@@ -138,14 +136,14 @@
         }
         public void setHeight(float h) {
             if (DEBUG_SCALE) Log.v(TAG, "SetHeight: setting to " + h);
-            mView.setContentHeight((int) h);
+            mView.setActualHeight((int) h);
             mCurrentHeight = h;
         }
         public float getHeight() {
-            return mView.getContentHeight();
+            return mView.getActualHeight();
         }
-        public int getNaturalHeight(int maximum) {
-            return Math.min(maximum, mView.getMaxContentHeight());
+        public int getNaturalHeight() {
+            return mView.getMaxContentHeight();
         }
     }
 
@@ -194,7 +192,7 @@
 
     private float clamp(float target) {
         float out = target;
-        out = out < mSmallSize ? mSmallSize : (out > mLargeSize ? mLargeSize : out);
+        out = out < mSmallSize ? mSmallSize : out;
         out = out > mNaturalHeight ? mNaturalHeight : out;
         return out;
     }
@@ -381,8 +379,8 @@
     }
 
     private boolean isFullyExpanded(ExpandableView underFocus) {
-        return underFocus.areChildrenExpanded() || underFocus.getIntrinsicHeight()
-                - underFocus.getBottomDecorHeight() == underFocus.getMaxContentHeight();
+        return underFocus.getIntrinsicHeight() == underFocus.getMaxContentHeight()
+                && (!underFocus.isSummaryWithChildren() || underFocus.areChildrenExpanded());
     }
 
     @Override
@@ -452,9 +450,7 @@
                     mScaler.setHeight(newHeight);
                     mLastMotionY = ev.getRawY();
                     if (isFinished) {
-                        mCallback.setUserExpandedChild(mResizedView, expanded);
                         mCallback.expansionStateChanged(false);
-                        return false;
                     } else {
                         mCallback.expansionStateChanged(true);
                     }
@@ -509,9 +505,11 @@
         mScaler.setView(v);
         mOldHeight = mScaler.getHeight();
         mCurrentHeight = mOldHeight;
-        if (mCallback.canChildBeExpanded(v)) {
+        boolean canBeExpanded = mCallback.canChildBeExpanded(v);
+        if (canBeExpanded) {
             if (DEBUG) Log.d(TAG, "working on an expandable child");
-            mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+            mNaturalHeight = mScaler.getNaturalHeight();
+            mSmallSize = v.getMinHeight();
         } else {
             if (DEBUG) Log.d(TAG, "working on a non-expandable child");
             mNaturalHeight = mOldHeight;
@@ -527,19 +525,22 @@
         if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView);
 
         float currentHeight = mScaler.getHeight();
-        float targetHeight = mSmallSize;
         float h = mScaler.getHeight();
         final boolean wasClosed = (mOldHeight == mSmallSize);
+        boolean nowExpanded;
+        int naturalHeight = mScaler.getNaturalHeight();
         if (wasClosed) {
-            targetHeight = (force || currentHeight > mSmallSize) ? mNaturalHeight : mSmallSize;
+            nowExpanded = (force || currentHeight > mOldHeight);
         } else {
-            targetHeight = (force || currentHeight < mNaturalHeight) ? mSmallSize : mNaturalHeight;
+            nowExpanded = !force && currentHeight >= mOldHeight;
         }
+        nowExpanded |= mNaturalHeight == mSmallSize;
         if (mScaleAnimation.isRunning()) {
             mScaleAnimation.cancel();
         }
-        mCallback.setUserExpandedChild(mResizedView, targetHeight == mNaturalHeight);
+        mCallback.setUserExpandedChild(mResizedView, nowExpanded);
         mCallback.expansionStateChanged(false);
+        float targetHeight = nowExpanded ? naturalHeight : mSmallSize;
         if (targetHeight != currentHeight) {
             mScaleAnimation.setFloatValues(targetHeight);
             mScaleAnimation.setupStartValues();
diff --git a/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java b/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java
new file mode 100644
index 0000000..3362650
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/QSQuickTileView.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.ImageView;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileBaseView;
+
+public class QSQuickTileView extends QSTileBaseView {
+
+    private final int mPadding;
+    private final ImageView mIcon;
+
+    public QSQuickTileView(Context context) {
+        super(context);
+        mPadding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
+        mIcon = createIcon();
+        addView(mIcon);
+    }
+
+    protected ImageView createIcon() {
+        final ImageView icon = new ImageView(mContext);
+        icon.setId(android.R.id.icon);
+        icon.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+        return icon;
+    }
+
+    @Override
+    public void init(OnClickListener click, OnClickListener clickSecondary,
+                     OnLongClickListener longClick) {
+        setClickable(true);
+        setOnClickListener(click);
+    }
+
+    @Override
+    protected void handleStateChanged(QSTile.State state) {
+        mIcon.setImageDrawable(state.icon.getDrawable(getContext()));
+        setContentDescription(state.contentDescription);
+    }
+
+    @Override
+    public boolean setType(int type) {
+        return false;
+    }
+
+    @Override
+    public View updateAccessibilityOrder(View previousView) {
+        return this;
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        mIcon.measure(exactly(getMeasuredWidth() - 2 * mPadding),
+                exactly(getMeasuredHeight() - 2 * mPadding));
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        layout(mIcon, mPadding, mPadding);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 1d0bfe7..9a4cd93 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -27,4 +27,9 @@
     void cancelPreloadingRecents();
     void showNextAffiliatedTask();
     void showPrevAffiliatedTask();
+
+    /**
+     * Docks the top-most task and opens recents.
+     */
+    void dockTopTask();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index c6bcfc4..794e900 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -566,7 +566,7 @@
 
     public static final class TileRecord extends Record {
         public QSTile<?> tile;
-        public QSTileView tileView;
+        public QSTileBaseView tileView;
         public int row;
         public int col;
         public boolean scanState;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 61cb224..5d928d6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -98,7 +98,7 @@
         return mHost;
     }
 
-    public QSTileView createTileView(Context context) {
+    public QSTileBaseView createTileView(Context context) {
         return new QSTileView(context);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
new file mode 100644
index 0000000..72fc88d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+ */
+
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+public abstract class QSTileBaseView extends ViewGroup {
+
+    public static final int QS_TYPE_NORMAL = 0;
+    public static final int QS_TYPE_DUAL   = 1;
+    public static final int QS_TYPE_QUICK  = 2;
+
+    private final H mHandler = new H();
+
+    public QSTileBaseView(Context context) {
+        super(context);
+    }
+
+    public QSTileBaseView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+
+    public void onStateChanged(QSTile.State state) {
+        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
+    }
+
+    public abstract void init(OnClickListener click, OnClickListener clickSecondary,
+                              OnLongClickListener longClick);
+    public abstract View updateAccessibilityOrder(View previousView);
+    public abstract boolean setType(int type);
+
+    protected abstract void handleStateChanged(QSTile.State state);
+
+    protected static int exactly(int size) {
+        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+    }
+
+    protected static void layout(View child, int left, int top) {
+        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+    }
+
+    private class H extends Handler {
+        private static final int STATE_CHANGED = 1;
+        public H() {
+            super(Looper.getMainLooper());
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (msg.what == STATE_CHANGED) {
+                handleStateChanged((QSTile.State) msg.obj);
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index d914beb..cc264a0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -44,18 +44,13 @@
 import java.util.Objects;
 
 /** View that represents a standard quick settings tile. **/
-public class QSTileView extends ViewGroup {
+public class QSTileView extends QSTileBaseView {
     private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
             Typeface.NORMAL);
 
-    public static final int QS_TYPE_NORMAL = 0;
-    public static final int QS_TYPE_DUAL   = 1;
-    public static final int QS_TYPE_QUICK  = 2;
-
     protected final Context mContext;
     private final View mIcon;
     private final View mDivider;
-    private final H mHandler = new H();
     private final int mIconSizePx;
     private final int mTileSpacingPx;
     private int mTilePaddingTopPx;
@@ -291,10 +286,6 @@
         return MeasureSpec.EXACTLY;
     }
 
-    private static int exactly(int size) {
-        return MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
-    }
-
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int w = getMeasuredWidth();
@@ -334,10 +325,6 @@
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
 
-    private static void layout(View child, int left, int top) {
-        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
-    }
-
     protected void handleStateChanged(QSTile.State state) {
         if (mIcon instanceof ImageView) {
             setIcon((ImageView) mIcon, state);
@@ -369,10 +356,6 @@
         }
     }
 
-    public void onStateChanged(QSTile.State state) {
-        mHandler.obtainMessage(H.STATE_CHANGED, state).sendToTarget();
-    }
-
     /**
      * Update the accessibility order for this view.
      *
@@ -392,17 +375,4 @@
         firstView.setAccessibilityTraversalAfter(previousView.getId());
         return lastView;
     }
-
-    private class H extends Handler {
-        private static final int STATE_CHANGED = 1;
-        public H() {
-            super(Looper.getMainLooper());
-        }
-        @Override
-        public void handleMessage(Message msg) {
-            if (msg.what == STATE_CHANGED) {
-                handleStateChanged((State) msg.obj);
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index a2d9ef0..6a053be 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -19,6 +19,8 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.view.Gravity;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
@@ -58,6 +60,7 @@
         ArrayList<QSTile<?>> quickTiles = new ArrayList<>();
         for (QSTile<?> tile : tiles) {
             if (tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
+                Log.d("QSPanel", "Adding " + tile.getTileSpec());
                 quickTiles.add(tile);
             }
             if (quickTiles.size() == 2) {
@@ -71,16 +74,17 @@
 
         public HeaderTileLayout(Context context) {
             super(context);
+            setGravity(Gravity.CENTER_VERTICAL);
             setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
-            int qsCompensation = (int)
-                    context.getResources().getDimension(R.dimen.qs_header_neg_padding);
-            setPadding(0, qsCompensation, 0, 0);
+
+            int padding =
+                    mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
             ImageView downArrow = new ImageView(context);
             downArrow.setImageResource(R.drawable.ic_expand_more);
             downArrow.setImageTintList(ColorStateList.valueOf(context.getResources().getColor(
                     android.R.color.white, null)));
             downArrow.setLayoutParams(generateLayoutParams());
-            downArrow.setPadding(0, -qsCompensation, 0, 0);
+            downArrow.setPadding(padding, padding, padding, padding);
             addView(downArrow);
             setOrientation(LinearLayout.HORIZONTAL);
         }
@@ -95,7 +99,9 @@
         }
 
         private LayoutParams generateLayoutParams() {
-            LayoutParams lp = new LayoutParams(0, LayoutParams.MATCH_PARENT);
+            int size =
+                    mContext.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_size);
+            LayoutParams lp = new LayoutParams(0, size);
             lp.weight = 1;
             return lp;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index f3ad9d8..e2d2ffb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -27,13 +27,12 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataController;
 import com.android.systemui.statusbar.policy.NetworkController.MobileDataController.DataUsageInfo;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
 
 /** Quick settings tile: Cellular **/
@@ -74,7 +73,7 @@
     }
 
     @Override
-    public QSTileView createTileView(Context context) {
+    public QSTileBaseView createTileView(Context context) {
         return new SignalTileView(context);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java
index 13ccaaa..b77191e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 
-/** Quick settings tile: Wifi **/
+/** Quick settings tile: Airplane mode **/
 public class QAirplaneTile extends AirplaneModeTile {
 
     public QAirplaneTile(Host host) {
@@ -26,6 +29,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java
index 02975cb..4fe7e45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 
 /** Quick settings tile: Bluetooth **/
@@ -26,6 +29,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java
index 31035cd..e115755e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 
-/** Quick settings tile: Wifi **/
+/** Quick settings tile: Flashlight **/
 public class QFlashlightTile extends FlashlightTile {
 
     public QFlashlightTile(Host host) {
@@ -26,6 +29,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
index 3675f02..8b3013a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
@@ -15,11 +15,14 @@
  */
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.R;
 
 public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.Callback {
 
@@ -31,6 +34,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java
index e066bab..5f5cab5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 
 /** Quick settings tile: Rotation **/
@@ -26,6 +29,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
index b157275..f0fe87d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.Context;
+import com.android.systemui.QSQuickTileView;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.statusbar.policy.WifiIcons;
 
@@ -27,6 +30,11 @@
     }
 
     @Override
+    public QSTileBaseView createTileView(Context context) {
+        return new QSQuickTileView(context);
+    }
+
+    @Override
     public int getTileType() {
         return QSTileView.QS_TYPE_QUICK;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 91e0218..3763618 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -30,6 +30,7 @@
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.SignalTileView;
 import com.android.systemui.statusbar.policy.NetworkController;
@@ -94,7 +95,7 @@
     }
 
     @Override
-    public QSTileView createTileView(Context context) {
+    public QSTileBaseView createTileView(Context context) {
         return new SignalTileView(context);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index 9781664..ebfacac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -37,8 +37,12 @@
             public static final boolean EnableTaskFiltering = false;
             // Enables dismiss-all
             public static final boolean EnableDismissAll = false;
+            // Enables fast-toggling
+            public static final boolean EnableFastToggleRecents = false;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
+            // This disables the search bar integration
+            public static final boolean DisableSearchBar = true;
             // This disables the bitmap and icon caches
             public static final boolean DisableBackgroundCache = false;
             // Enables the simulated task affiliations
@@ -60,8 +64,6 @@
         }
 
         public static class TaskStackView {
-            public static final int TaskStackMinOverscrollRange = 32;
-            public static final int TaskStackMaxOverscrollRange = 128;
             public static final int FilterStartDelay = 25;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index ae79fe2..4d40cb7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -34,6 +34,7 @@
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.RecentsTaskLoader;
 
 import java.util.ArrayList;
 
@@ -51,7 +52,10 @@
     public final static int EVENT_BUS_PRIORITY = 1;
     public final static int BIND_TO_SYSTEM_USER_RETRY_DELAY = 5000;
 
-    private SystemServicesProxy mSystemServicesProxy;
+    private static SystemServicesProxy sSystemServicesProxy;
+    private static RecentsTaskLoader sTaskLoader;
+    private static RecentsConfiguration sConfiguration;
+
     private Handler mHandler;
     private RecentsImpl mImpl;
 
@@ -118,20 +122,35 @@
         return mSystemUserCallbacks;
     }
 
+    public static RecentsTaskLoader getTaskLoader() {
+        return sTaskLoader;
+    }
+
+    public static SystemServicesProxy getSystemServices() {
+        return sSystemServicesProxy;
+    }
+
+    public static RecentsConfiguration getConfiguration() {
+        return sConfiguration;
+    }
+
     @Override
     public void start() {
-        mSystemServicesProxy = new SystemServicesProxy(mContext);
+        sSystemServicesProxy = new SystemServicesProxy(mContext);
+        sTaskLoader = new RecentsTaskLoader(mContext);
+        sConfiguration = new RecentsConfiguration(mContext);
         mHandler = new Handler();
         mImpl = new RecentsImpl(mContext);
 
         // Register with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
+        EventBus.getDefault().register(sTaskLoader, EVENT_BUS_PRIORITY);
 
         // Due to the fact that RecentsActivity is per-user, we need to establish and interface for
         // the system user's Recents component to pass events (like show/hide/toggleRecents) to the
         // secondary user, and vice versa (like visibility change, screen pinning).
-        final int processUser = mSystemServicesProxy.getProcessUser();
-        if (mSystemServicesProxy.isSystemUser(processUser)) {
+        final int processUser = sSystemServicesProxy.getProcessUser();
+        if (sSystemServicesProxy.isSystemUser(processUser)) {
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
             mSystemUserCallbacks = new RecentsSystemUser(mContext, mImpl);
@@ -153,8 +172,8 @@
      */
     @Override
     public void showRecents(boolean triggeredFromAltTab, View statusBarView) {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.showRecents(triggeredFromAltTab);
         } else {
             if (mSystemUserCallbacks != null) {
@@ -178,8 +197,8 @@
      */
     @Override
     public void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
         } else {
             if (mSystemUserCallbacks != null) {
@@ -203,8 +222,8 @@
      */
     @Override
     public void toggleRecents(Display display, int layoutDirection, View statusBarView) {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.toggleRecents();
         } else {
             if (mSystemUserCallbacks != null) {
@@ -228,8 +247,8 @@
      */
     @Override
     public void preloadRecents() {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.preloadRecents();
         } else {
             if (mSystemUserCallbacks != null) {
@@ -250,8 +269,8 @@
 
     @Override
     public void cancelPreloadingRecents() {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.cancelPreloadingRecents();
         } else {
             if (mSystemUserCallbacks != null) {
@@ -271,6 +290,11 @@
     }
 
     @Override
+    public void dockTopTask() {
+        mImpl.dockTopTask();
+    }
+
+    @Override
     public void showNextAffiliatedTask() {
         mImpl.showNextAffiliatedTask();
     }
@@ -284,8 +308,8 @@
      * Updates on configuration change.
      */
     public void onConfigurationChanged(Configuration newConfig) {
-        int currentUser = mSystemServicesProxy.getCurrentUser();
-        if (mSystemServicesProxy.isSystemUser(currentUser)) {
+        int currentUser = sSystemServicesProxy.getCurrentUser();
+        if (sSystemServicesProxy.isSystemUser(currentUser)) {
             mImpl.onConfigurationChanged();
         } else {
             if (mSystemUserCallbacks != null) {
@@ -350,7 +374,7 @@
      * Attempts to register with the system user.
      */
     private void registerWithSystemUser() {
-        final int processUser = mSystemServicesProxy.getProcessUser();
+        final int processUser = sSystemServicesProxy.getProcessUser();
         postToSystemUser(new Runnable() {
             @Override
             public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 199d985..4d575bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -41,15 +41,22 @@
 import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.ResizeTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
 import com.android.systemui.recents.misc.Console;
+import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsPackageMonitor;
@@ -68,11 +75,14 @@
  */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks {
 
+    private final static String TAG = "RecentsActivity";
+    private final static boolean DEBUG = false;
+
     public final static int EVENT_BUS_PRIORITY = Recents.EVENT_BUS_PRIORITY + 1;
 
-    RecentsConfiguration mConfig;
     RecentsPackageMonitor mPackageMonitor;
     long mLastTabKeyEventTime;
+    boolean mFinishedOnStartup;
 
     // Top level views
     RecentsView mRecentsView;
@@ -94,6 +104,14 @@
     // Runnable to be executed after we paused ourselves
     Runnable mAfterPauseRunnable;
 
+    // The trigger to automatically launch the current task
+    DozeTrigger mIterateTrigger = new DozeTrigger(500, new Runnable() {
+        @Override
+        public void run() {
+            boolean dismissed = dismissRecentsToFocusedTask(false);
+        }
+    });
+
     /**
      * A common Runnable to finish Recents either by calling finish() (with a custom animation) or
      * launching Home with some ActivityOptions.  Generally we always launch home when we exit
@@ -137,7 +155,7 @@
                 dismissRecentsToHomeIfVisible(false);
             } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) {
                 // When the search activity changes, update the search widget view
-                SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+                SystemServicesProxy ssp = Recents.getSystemServices();
                 mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(context, mAppWidgetHost);
                 refreshSearchWidgetView();
             }
@@ -148,14 +166,15 @@
     void updateRecentsTasks() {
         // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
         // reconstructing the task stack
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
         if (plan == null) {
             plan = loader.createLoadPlan(this);
         }
 
         // Start loading tasks according to the load plan
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         if (!plan.hasTasks()) {
             loader.preloadTasks(plan, launchState.launchedFromHome);
         }
@@ -204,15 +223,19 @@
                 mEmptyView = mEmptyViewStub.inflate();
             }
             mEmptyView.setVisibility(View.VISIBLE);
-            mRecentsView.setSearchBarVisibility(View.GONE);
+            if (!Constants.DebugFlags.App.DisableSearchBar) {
+                mRecentsView.setSearchBarVisibility(View.GONE);
+            }
         } else {
             if (mEmptyView != null) {
                 mEmptyView.setVisibility(View.GONE);
             }
-            if (mRecentsView.hasValidSearchBar()) {
-                mRecentsView.setSearchBarVisibility(View.VISIBLE);
-            } else {
-                refreshSearchWidgetView();
+            if (!Constants.DebugFlags.App.DisableSearchBar) {
+                if (mRecentsView.hasValidSearchBar()) {
+                    mRecentsView.setSearchBarVisibility(View.VISIBLE);
+                } else {
+                    refreshSearchWidgetView();
+                }
             }
         }
 
@@ -238,10 +261,28 @@
         MetricsLogger.histogram(this, "overview_task_count", taskCount);
     }
 
-    /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
+    /**
+     * Dismisses recents if we are already visible and the intent is to toggle the recents view.
+     */
+    boolean dismissRecentsToFocusedTask(boolean checkFilteredStackState) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+            // If we currently have filtered stacks, then unfilter those first
+            if (checkFilteredStackState &&
+                    mRecentsView.unfilterFilteredStacks()) return true;
+            // If we have a focused Task, launch that Task now
+            if (mRecentsView.launchFocusedTask()) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Dismisses recents if we are already visible and the intent is to toggle the recents view.
+     */
     boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-        SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // If we currently have filtered stacks, then unfilter those first
             if (checkFilteredStackState &&
@@ -284,7 +325,7 @@
 
     /** Dismisses Recents directly to Home if we currently aren't transitioning. */
     boolean dismissRecentsToHomeIfVisible(boolean animated) {
-        SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // Return to Home
             dismissRecentsToHome(animated);
@@ -297,20 +338,26 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        mFinishedOnStartup = false;
+
+        // In the case that the activity starts up before the Recents component has initialized
+        // (usually when debugging/pushing the SysUI apk), just finish this activity.
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp == null) {
+            mFinishedOnStartup = true;
+            finish();
+            return;
+        }
 
         // Register this activity with the event bus
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
 
-        // For the non-primary user, ensure that the SystemServicesProxy and configuration is
-        // initialized
-        RecentsTaskLoader.initialize(this);
-        SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-        mConfig = RecentsConfiguration.initialize(this, ssp);
-        mConfig.update(this, ssp, ssp.getWindowRect());
-        mPackageMonitor = new RecentsPackageMonitor();
-
         // Initialize the widget host (the host id is static and does not change)
-        mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
+        if (!Constants.DebugFlags.App.DisableSearchBar) {
+            mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
+        }
+        mPackageMonitor = new RecentsPackageMonitor();
+        mPackageMonitor.register(this);
 
         // Set the Recents layout
         setContentView(R.layout.recents);
@@ -323,12 +370,16 @@
         mScrimViews = new SystemBarScrimViews(this);
 
         // Bind the search app widget when we first start up
-        mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
+        if (!Constants.DebugFlags.App.DisableSearchBar) {
+            mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
+        }
 
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
+        if (!Constants.DebugFlags.App.DisableSearchBar) {
+            filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
+        }
         registerReceiver(mSystemBroadcastReceiver, filter);
     }
 
@@ -341,16 +392,6 @@
     @Override
     protected void onStart() {
         super.onStart();
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-        MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        SystemServicesProxy ssp = loader.getSystemServicesProxy();
-
-        // Notify that recents is now visible
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
-
-        // Register any broadcast receivers for the task loader
-        mPackageMonitor.register(this);
 
         // Update the recent tasks
         updateRecentsTasks();
@@ -358,6 +399,8 @@
         // If this is a new instance from a configuration change, then we have to manually trigger
         // the enter animation state, or if recents was relaunched by AM, without going through
         // the normal mechanisms
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         boolean wasLaunchedByAm = !launchState.launchedFromHome &&
                 !launchState.launchedFromAppWithThumbnail;
         if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
@@ -367,6 +410,23 @@
         if (!launchState.launchedHasConfigurationChanged) {
             mRecentsView.disableLayersForOneFrame();
         }
+
+        // Notify that recents is now visible
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+
+        MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        final RecentsActivityLaunchState state = Recents.getConfiguration().getLaunchState();
+        if (state.startHidden) {
+            state.startHidden = false;
+            mRecentsView.setVisibility(View.INVISIBLE);
+        }
     }
 
     @Override
@@ -376,45 +436,56 @@
             mRecentsView.post(mAfterPauseRunnable);
             mAfterPauseRunnable = null;
         }
+
+        if (Constants.DebugFlags.App.EnableFastToggleRecents) {
+            // Stop the fast-toggle dozer
+            mIterateTrigger.stopDozing();
+        }
     }
 
     @Override
     protected void onStop() {
         super.onStop();
-        MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        SystemServicesProxy ssp = loader.getSystemServicesProxy();
 
         // Notify that recents is now hidden
+        SystemServicesProxy ssp = Recents.getSystemServices();
         EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
 
-        // Notify the views that we are no longer visible
-        mRecentsView.onRecentsHidden();
-
-        // Unregister any broadcast receivers for the task loader
-        mPackageMonitor.unregister();
-
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
         // wait on the system to send a signal that was never queued.
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         launchState.launchedFromHome = false;
         launchState.launchedFromSearchHome = false;
         launchState.launchedFromAppWithThumbnail = false;
         launchState.launchedToTaskId = -1;
         launchState.launchedWithAltTab = false;
         launchState.launchedHasConfigurationChanged = false;
+
+        MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
     }
 
     @Override
     protected void onDestroy() {
         super.onDestroy();
 
+        // In the case that the activity finished on startup, just skip the unregistration below
+        if (mFinishedOnStartup) {
+            return;
+        }
+
         // Unregister the system broadcast receivers
         unregisterReceiver(mSystemBroadcastReceiver);
 
+        // Unregister any broadcast receivers for the task loader
+        mPackageMonitor.unregister();
+
         // Stop listening for widget package changes if there was one bound
-        mAppWidgetHost.stopListening();
+        if (!Constants.DebugFlags.App.DisableSearchBar) {
+            mAppWidgetHost.stopListening();
+        }
+
         EventBus.getDefault().unregister(this);
     }
 
@@ -432,7 +503,7 @@
 
     @Override
     public void onTrimMemory(int level) {
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         if (loader != null) {
             loader.onTrimMemory(level);
         }
@@ -448,22 +519,27 @@
                 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
                     // Focus the next task in the stack
                     final boolean backward = event.isShiftPressed();
-                    mRecentsView.focusNextTask(!backward);
+                    if (backward) {
+                        EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
+                    } else {
+                        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+                    }
                     mLastTabKeyEventTime = SystemClock.elapsedRealtime();
                 }
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_UP: {
-                mRecentsView.focusNextTask(true);
+                EventBus.getDefault().send(new FocusNextTaskViewEvent());
                 return true;
             }
             case KeyEvent.KEYCODE_DPAD_DOWN: {
-                mRecentsView.focusNextTask(false);
+                EventBus.getDefault().send(new FocusPreviousTaskViewEvent());
                 return true;
             }
             case KeyEvent.KEYCODE_DEL:
             case KeyEvent.KEYCODE_FORWARD_DEL: {
-                mRecentsView.dismissFocusedTask();
+                EventBus.getDefault().send(new DismissFocusedTaskViewEvent());
+
                 // Keep track of deletions by keyboard
                 MetricsLogger.histogram(this, "overview_task_dismissed_source",
                         Constants.Metrics.DismissSourceKeyboard);
@@ -477,7 +553,7 @@
 
     @Override
     public void onUserInteraction() {
-        mRecentsView.onUserInteraction();
+        EventBus.getDefault().send(new UserInteractionEvent());
     }
 
     @Override
@@ -523,6 +599,16 @@
         dismissRecentsToFocusedTaskOrHome(true /* checkFilteredStackState */);
     }
 
+    public final void onBusEvent(IterateRecentsEvent event) {
+        // Focus the next task
+        EventBus.getDefault().send(new FocusNextTaskViewEvent());
+        mIterateTrigger.poke();
+    }
+
+    public final void onBusEvent(UserInteractionEvent event) {
+        mIterateTrigger.stopDozing();
+    }
+
     public final void onBusEvent(HideRecentsEvent event) {
         if (event.triggeredFromAltTab) {
             // If we are hiding from releasing Alt-Tab, dismiss Recents to the focused app
@@ -539,18 +625,39 @@
         // Try and start the enter animation (or restart it on configuration changed)
         ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null);
         ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
-        mRecentsView.startEnterRecentsAnimation(ctx);
+        ctx.postAnimationTrigger.increment();
         if (mSearchWidgetInfo != null) {
-            ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
-                @Override
-                public void run() {
-                    // Start listening for widget package changes if there is one bound
-                    if (mAppWidgetHost != null) {
-                        mAppWidgetHost.startListening();
+            if (!Constants.DebugFlags.App.DisableSearchBar) {
+                ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+                    @Override
+                    public void run() {
+                        // Start listening for widget package changes if there is one bound
+                        if (mAppWidgetHost != null) {
+                            mAppWidgetHost.startListening();
+                        }
                     }
-                }
-            });
+                });
+            }
         }
+        ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
+            @Override
+            public void run() {
+                // If we are not launching with alt-tab and fast-toggle is enabled, then start
+                // the dozer now
+                RecentsConfiguration config = Recents.getConfiguration();
+                RecentsActivityLaunchState launchState = config.getLaunchState();
+                if (Constants.DebugFlags.App.EnableFastToggleRecents &&
+                        !launchState.launchedWithAltTab) {
+                    mIterateTrigger.startDozing();
+                }
+            }
+        });
+        mRecentsView.startEnterRecentsAnimation(ctx);
+        ctx.postAnimationTrigger.decrement();
+    }
+
+    public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) {
+        mRecentsView.setVisibility(View.VISIBLE);
     }
 
     public final void onBusEvent(AppWidgetProviderChangedEvent event) {
@@ -559,9 +666,8 @@
 
     public final void onBusEvent(ShowApplicationInfoEvent event) {
         // Create a new task stack with the application info details activity
-        Intent baseIntent = event.task.key.baseIntent;
         Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
-                Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
+                Uri.fromParts("package", event.task.key.getComponent().getPackageName(), null));
         intent.setComponent(intent.resolveActivity(getPackageManager()));
         TaskStackBuilder.create(this)
                 .addNextIntentWithParentStack(intent).startActivities(null,
@@ -571,13 +677,14 @@
         MetricsLogger.count(this, "overview_app_info", 1);
     }
 
-    public final void onBusEvent(DismissTaskEvent event) {
+    public final void onBusEvent(DismissTaskViewEvent event) {
         // Remove any stored data from the loader
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         loader.deleteTaskData(event.task, false);
 
         // Remove the task from activity manager
-        loader.getSystemServicesProxy().removeTask(event.task.key.id);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ssp.removeTask(event.task.key.id);
     }
 
     public final void onBusEvent(ResizeTaskEvent event) {
@@ -602,7 +709,7 @@
 
     private void refreshSearchWidgetView() {
         if (mSearchWidgetInfo != null) {
-            SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
+            SystemServicesProxy ssp = Recents.getSystemServices();
             int searchWidgetId = ssp.getSearchAppWidgetId(this);
             mSearchWidgetHostView = (RecentsAppWidgetHostView) mAppWidgetHost.createView(
                     this, searchWidgetId, mSearchWidgetInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index e2e0e918..31ce569 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -28,8 +28,6 @@
  */
 public class RecentsActivityLaunchState {
 
-    public RecentsConfiguration mConfig;
-
     public boolean launchedWithAltTab;
     public boolean launchedWithNoRecentTasks;
     public boolean launchedFromAppWithThumbnail;
@@ -37,14 +35,11 @@
     public boolean launchedFromSearchHome;
     public boolean launchedReuseTaskStackViews;
     public boolean launchedHasConfigurationChanged;
+    public boolean startHidden;
     public int launchedToTaskId;
     public int launchedNumVisibleTasks;
     public int launchedNumVisibleThumbnails;
 
-    RecentsActivityLaunchState(RecentsConfiguration config) {
-        mConfig = config;
-    }
-
     /** Called when the configuration has changed, and we want to reset any configuration specific
      * members. */
     public void updateOnConfigurationChange() {
@@ -56,7 +51,7 @@
 
     /** Returns whether the status bar scrim should be animated when shown for the first time. */
     public boolean shouldAnimateStatusBarScrim() {
-        return launchedFromHome;
+        return true;
     }
 
     /** Returns whether the status bar scrim should be visible. */
@@ -72,6 +67,7 @@
     /** Returns whether the nav bar scrim should be visible. */
     public boolean hasNavBarScrim() {
         // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
-        return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar;
+        RecentsConfiguration config = Recents.getConfiguration();
+        return !launchedWithNoRecentTasks && !config.hasTransposedNavBar;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index f60dcb2..e2f20fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -28,7 +28,6 @@
  * tied to the current activity.
  */
 public class RecentsConfiguration {
-    static RecentsConfiguration sInstance;
 
     private static final int LARGE_SCREEN_MIN_DP = 600;
     private static final int XLARGE_SCREEN_MIN_DP = 720;
@@ -53,7 +52,7 @@
     public static final int SVELTE_DISABLE_LOADING = 3;
 
     // Launch states
-    public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(this);
+    public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState();
 
     // TODO: Values determined by the current context, needs to be refactored into something that is
     //       agnostic of the activity context, but still calculable from the Recents component for
@@ -79,10 +78,10 @@
     /** Dev options and global settings */
     public boolean lockToAppEnabled;
 
-    /** Private constructor */
-    private RecentsConfiguration(Context context, SystemServicesProxy ssp) {
+    public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
+        SystemServicesProxy ssp = Recents.getSystemServices();
         Context appContext = context.getApplicationContext();
         Resources res = appContext.getResources();
         useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
@@ -111,8 +110,7 @@
     void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
         // Only update resources that can change after the first load, either through developer
         // settings or via multi window
-        lockToAppEnabled = ssp.getSystemSetting(context,
-                Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        lockToAppEnabled = ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
         hasDockedTasks = ssp.hasDockedTask();
 
         // Recompute some values based on the given state, since we can not rely on the resource
@@ -122,19 +120,6 @@
         hasTransposedSearchBar = isLandscape && isLargeScreen && !isXLargeScreen;
     }
 
-    /** Updates the configuration to the current context */
-    public static RecentsConfiguration initialize(Context context, SystemServicesProxy ssp) {
-        if (sInstance == null) {
-            sInstance = new RecentsConfiguration(context, ssp);
-        }
-        return sInstance;
-    }
-
-    /** Returns the current recents configuration */
-    public static RecentsConfiguration getInstance() {
-        return sInstance;
-    }
-
     /**
      * Returns the activity launch state.
      * TODO: This will be refactored out of RecentsConfiguration.
@@ -143,8 +128,10 @@
         return mLaunchState;
     }
 
-    /** Called when the configuration has changed, and we want to reset any configuration specific
-     * members. */
+    /**
+     * Called when the configuration has changed, and we want to reset any configuration specific
+     * members.
+     */
     public void updateOnConfigurationChange() {
         mLaunchState.updateOnConfigurationChange();
     }
@@ -164,7 +151,8 @@
         } else {
             // In portrait, the search bar appears on the top (which already has the inset)
             int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left);
-            taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom,
+            int top = searchBarBounds.isEmpty() ? topInset : 0;
+            taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom + top,
                     windowBounds.right - swInset, windowBounds.bottom);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 0d1a54e..243c0e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents;
 
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
@@ -26,13 +28,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.os.AsyncTask;
+import android.graphics.RectF;
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.MutableBoolean;
+import android.view.AppTransitionAnimationSpec;
 import android.view.LayoutInflater;
 import android.view.View;
+
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
@@ -40,10 +44,13 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationStartedEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
+import com.android.systemui.recents.events.activity.IterateRecentsEvent;
+import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.misc.Console;
+import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -51,7 +58,7 @@
 import com.android.systemui.recents.model.TaskGrouping;
 import com.android.systemui.recents.model.TaskStack;
 import com.android.systemui.recents.views.TaskStackView;
-import com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm;
+import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -63,16 +70,16 @@
  * be called remotely from the system user.
  */
 public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
-        implements ActivityOptions.OnAnimationStartedListener {
+        implements ActivityOptions.OnAnimationStartedListener, ActivityOptions.OnAnimationFinishedListener {
 
     private final static String TAG = "RecentsImpl";
+    private final static boolean DEBUG = false;
 
     private final static int sMinToggleDelay = 350;
 
     public final static String RECENTS_PACKAGE = "com.android.systemui";
     public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
 
-
     /**
      * An implementation of ITaskStackListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
@@ -97,8 +104,8 @@
             /*
             RecentsConfiguration config = RecentsConfiguration.getInstance();
             if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
-                RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                SystemServicesProxy ssp = loader.getSystemServicesProxy();
+                RecentsTaskLoader loader = Recents.getTaskLoader();
+                SystemServicesProxy ssp = Recents.getSystemServices();
                 ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
 
                 // Load the next task only if we aren't svelte
@@ -121,10 +128,9 @@
         }
     }
 
-    static RecentsTaskLoadPlan sInstanceLoadPlan;
+    private static RecentsTaskLoadPlan sInstanceLoadPlan;
 
     Context mContext;
-    SystemServicesProxy mSystemServicesProxy;
     Handler mHandler;
     TaskStackListenerImpl mTaskStackListener;
     RecentsAppWidgetHost mAppWidgetHost;
@@ -133,7 +139,6 @@
     boolean mCanReuseTaskStackViews = true;
 
     // Task launching
-    RecentsConfiguration mConfig;
     Rect mSearchBarBounds = new Rect();
     Rect mTaskStackBounds = new Rect();
     Rect mLastTaskViewBounds = new Rect();
@@ -158,19 +163,20 @@
 
     public RecentsImpl(Context context) {
         mContext = context;
-        mSystemServicesProxy = new SystemServicesProxy(mContext);
         mHandler = new Handler();
         mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
         Resources res = mContext.getResources();
-        RecentsTaskLoader.initialize(mContext);
         LayoutInflater inflater = LayoutInflater.from(mContext);
 
+        // Initialize the static foreground thread
+        ForegroundThread.get();
+
         // Register the task stack listener
         mTaskStackListener = new TaskStackListenerImpl(mHandler);
-        mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ssp.registerTaskStackListener(mTaskStackListener);
 
         // Initialize the static configuration resources
-        mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
         mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
         mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
         mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
@@ -182,7 +188,7 @@
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
         loader.preloadTasks(plan, true /* isTopTaskHome */);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
@@ -201,7 +207,7 @@
     public void onConfigurationChanged() {
         // Don't reuse task stack views if the configuration changes
         mCanReuseTaskStackViews = false;
-        mConfig.updateOnConfigurationChange();
+        Recents.getConfiguration().updateOnConfigurationChange();
     }
 
     /**
@@ -236,9 +242,10 @@
 
         try {
             // Check if the top task is in the home stack, and start the recents activity
-            ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
             MutableBoolean isTopTaskHome = new MutableBoolean(true);
-            if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
+            if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
                 startRecentsActivity(topTask, isTopTaskHome.value);
             }
         } catch (ActivityNotFoundException e) {
@@ -251,7 +258,7 @@
         if (mBootCompleted) {
             // Defer to the activity to handle hiding recents, if it handles it, then it must still
             // be visible
-            EventBus.getDefault().send(new HideRecentsEvent(triggeredFromAltTab,
+            EventBus.getDefault().post(new HideRecentsEvent(triggeredFromAltTab,
                     triggeredFromHomeKey));
         }
     }
@@ -261,25 +268,38 @@
         mTriggeredFromAltTab = false;
 
         try {
-            // If the user has toggled it too quickly, then just eat up the event here (it's better
-            // than showing a janky screenshot).
-            // NOTE: Ideally, the screenshot mechanism would take the window transform into account
-            if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
-                return;
-            }
-
-            // If Recents is the front most activity, then we should just communicate with it
-            // directly to launch the first task or dismiss itself
-            ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
             MutableBoolean isTopTaskHome = new MutableBoolean(true);
-            if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
-                // Notify recents to toggle itself
-                EventBus.getDefault().send(new ToggleRecentsEvent());
-                mLastToggleTime = SystemClock.elapsedRealtime();
+            if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
+                if (Constants.DebugFlags.App.EnableFastToggleRecents) {
+                    // Notify recents to move onto the next task
+                    EventBus.getDefault().post(new IterateRecentsEvent());
+                } else {
+                    // If the user has toggled it too quickly, then just eat up the event here (it's
+                    // better than showing a janky screenshot).
+                    // NOTE: Ideally, the screenshot mechanism would take the window transform into
+                    // account
+                    if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+                        return;
+                    }
+
+                    EventBus.getDefault().post(new ToggleRecentsEvent());
+                    mLastToggleTime = SystemClock.elapsedRealtime();
+                }
                 return;
             } else {
+                // If the user has toggled it too quickly, then just eat up the event here (it's
+                // better than showing a janky screenshot).
+                // NOTE: Ideally, the screenshot mechanism would take the window transform into
+                // account
+                if ((SystemClock.elapsedRealtime() - mLastToggleTime) < sMinToggleDelay) {
+                    return;
+                }
+
                 // Otherwise, start the recents activity
                 startRecentsActivity(topTask, isTopTaskHome.value);
+                mLastToggleTime = SystemClock.elapsedRealtime();
             }
         } catch (ActivityNotFoundException e) {
             Console.logRawError("Failed to launch RecentAppsIntent", e);
@@ -290,15 +310,18 @@
     public void preloadRecents() {
         // Preload only the raw task list into a new load plan (which will be consumed by the
         // RecentsActivity) only if there is a task to animate to.
-        ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
         MutableBoolean topTaskHome = new MutableBoolean(true);
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         sInstanceLoadPlan = loader.createLoadPlan(mContext);
-        if (topTask != null && !mSystemServicesProxy.isRecentsTopMost(topTask, topTaskHome)) {
+        if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
             sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
             loader.preloadTasks(sInstanceLoadPlan, topTaskHome.value);
             TaskStack stack = sInstanceLoadPlan.getTaskStack();
             if (stack.getTaskCount() > 0) {
+                // We try and draw the thumbnail transition bitmap in parallel before
+                // toggle/show recents is called
                 preCacheThumbnailTransitionBitmapAsync(topTask, stack, mDummyStackView);
             }
         }
@@ -311,8 +334,9 @@
 
     public void showRelativeAffiliatedTask(boolean showNextTask) {
         // Return early if there is no focused stack
-        int focusedStackId = mSystemServicesProxy.getFocusedStack();
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        int focusedStackId = ssp.getFocusedStack();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
         loader.preloadTasks(plan, true /* isTopTaskHome */);
         TaskStack focusedStack = plan.getTaskStack();
@@ -320,11 +344,11 @@
         // Return early if there are no tasks in the focused stack
         if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
-        ActivityManager.RunningTaskInfo runningTask = mSystemServicesProxy.getTopMostTask();
+        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
         // Return early if there is no running task (can't determine affiliated tasks in this case)
         if (runningTask == null) return;
         // Return early if the running task is in the home stack (optimization)
-        if (mSystemServicesProxy.isInHomeStack(runningTask.id)) return;
+        if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return;
 
         // Find the task in the recents list
         ArrayList<Task> tasks = focusedStack.getTasks();
@@ -360,11 +384,11 @@
         if (toTask == null) {
             if (numAffiliatedTasks > 1) {
                 if (showNextTask) {
-                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+                    ssp.startInPlaceAnimationOnFrontMostApplication(
                             ActivityOptions.makeCustomInPlaceAnimation(mContext,
                                     R.anim.recents_launch_next_affiliated_task_bounce));
                 } else {
-                    mSystemServicesProxy.startInPlaceAnimationOnFrontMostApplication(
+                    ssp.startInPlaceAnimationOnFrontMostApplication(
                             ActivityOptions.makeCustomInPlaceAnimation(mContext,
                                     R.anim.recents_launch_prev_affiliated_task_bounce));
                 }
@@ -378,10 +402,9 @@
         // Launch the task
         if (toTask.isActive) {
             // Bring an active task to the foreground
-            mSystemServicesProxy.moveTaskToFront(toTask.key.id, launchOpts);
+            ssp.moveTaskToFront(toTask.key.id, launchOpts);
         } else {
-            mSystemServicesProxy.startActivityFromRecents(mContext, toTask.key.id,
-                    toTask.activityLabel, launchOpts);
+            ssp.startActivityFromRecents(mContext, toTask.key.id, toTask.activityLabel, launchOpts);
         }
     }
 
@@ -397,6 +420,16 @@
         showRelativeAffiliatedTask(false);
     }
 
+    public void dockTopTask() {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
+        if (topTask != null && !SystemServicesProxy.isHomeStack(topTask.stackId)) {
+            ssp.startTaskInDockedMode(topTask.id,
+                    ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
+            showRecents(false /* triggeredFromAltTab */);
+        }
+    }
+
     /**
      * Returns the preloaded load plan and invalidates it.
      */
@@ -414,31 +447,32 @@
      *                               is not already bound (can be expensive)
      */
     private void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
-        Rect windowRect = mSystemServicesProxy.getWindowRect();
+        RecentsConfiguration config = Recents.getConfiguration();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect windowRect = ssp.getWindowRect();
 
         // Update the configuration for the current state
-        mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
+        config.update(mContext, ssp, ssp.getWindowRect());
 
-        if (tryAndBindSearchWidget) {
+        if (!Constants.DebugFlags.App.DisableSearchBar && tryAndBindSearchWidget) {
             // Try and pre-emptively bind the search widget on startup to ensure that we
             // have the right thumbnail bounds to animate to.
             // Note: We have to reload the widget id before we get the task stack bounds below
-            if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
-                mConfig.getSearchBarBounds(windowRect,
-                        mStatusBarHeight, mSearchBarBounds);
+            if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
+                config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds);
             }
         }
         Rect systemInsets = new Rect(0, mStatusBarHeight,
-                (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
-                (mConfig.hasTransposedNavBar ? 0 : mNavBarHeight));
-        mConfig.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
+                (config.hasTransposedNavBar ? mNavBarWidth : 0),
+                (config.hasTransposedNavBar ? 0 : mNavBarHeight));
+        config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
                 mSearchBarBounds, mTaskStackBounds);
 
         // Rebind the header bar and draw it for the transition
-        TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
+        TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
         Rect taskStackBounds = new Rect(mTaskStackBounds);
         algo.setSystemInsets(systemInsets);
-        algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
+        algo.initialize(taskStackBounds);
         Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
         if (!taskViewBounds.equals(mLastTaskViewBounds)) {
             mLastTaskViewBounds.set(taskViewBounds);
@@ -457,13 +491,12 @@
      * Preloads the icon of a task.
      */
     private void preloadIcon(ActivityManager.RunningTaskInfo task) {
-
         // Ensure that we load the running task's icon
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
         launchOpts.runningTaskId = task.id;
         launchOpts.loadThumbnails = false;
         launchOpts.onlyLoadForCache = true;
-        RecentsTaskLoader.getInstance().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
+        Recents.getTaskLoader().loadTasks(mContext, sInstanceLoadPlan, launchOpts);
     }
 
     /**
@@ -482,25 +515,25 @@
         final Task toTask = new Task();
         final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
                 topTask.id, toTask);
-        new AsyncTask<Void, Void, Bitmap>() {
+        ForegroundThread.getHandler().post(new Runnable() {
             @Override
-            protected Bitmap doInBackground(Void... params) {
-                return drawThumbnailTransitionBitmap(toTask, toTransform);
+            public void run() {
+                final Bitmap transitionBitmap = drawThumbnailTransitionBitmap(toTask, toTransform);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mThumbnailTransitionBitmapCache = transitionBitmap;
+                        mThumbnailTransitionBitmapCacheKey = toTask;
+                    }
+                });
             }
-
-            @Override
-            protected void onPostExecute(Bitmap bitmap) {
-                mThumbnailTransitionBitmapCache = bitmap;
-                mThumbnailTransitionBitmapCacheKey = toTask;
-            }
-        }.execute();
+        });
     }
 
     /**
      * Creates the activity options for a unknown state->recents transition.
      */
     private ActivityOptions getUnknownTransitionActivityOptions() {
-        mStartAnimationTriggered = false;
         return ActivityOptions.makeCustomAnimation(mContext,
                 R.anim.recents_from_unknown_enter,
                 R.anim.recents_from_unknown_exit,
@@ -511,7 +544,6 @@
      * Creates the activity options for a home->recents transition.
      */
     private ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) {
-        mStartAnimationTriggered = false;
         if (fromSearchHome) {
             return ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.recents_from_search_launcher_enter,
@@ -529,12 +561,44 @@
      */
     private ActivityOptions getThumbnailTransitionActivityOptions(
             ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+        if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
+            ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
+            stackView.getScroller().setStackScrollToInitialState();
+            ArrayList<Task> tasks = stack.getTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                Task task = tasks.get(i);
+                if (SystemServicesProxy.isFreeformStack(task.key.stackId)) {
+                    mTmpTransform = stackView.getStackAlgorithm().getStackTransform(task,
+                            stackView.getScroller().getStackScroll(), mTmpTransform, null);
+                    Rect toTaskRect = new Rect();
+                    mTmpTransform.rect.round(toTaskRect);
+                    Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
+                    specs.add(new AppTransitionAnimationSpec(task.key.id, thumbnail, toTaskRect));
+                }
+            }
+            AppTransitionAnimationSpec[] specsArray = new AppTransitionAnimationSpec[specs.size()];
+            specs.toArray(specsArray);
+            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+                    specsArray, mHandler, this, this);
+        } else {
+            // Update the destination rect
+            Task toTask = new Task();
+            TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
+                    topTask.id, toTask);
+            RectF toTaskRect = toTransform.rect;
+            Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
+            if (thumbnail != null) {
+                return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+                        thumbnail, (int) toTaskRect.left, (int) toTaskRect.top,
+                        (int) toTaskRect.width(), (int) toTaskRect.height(), mHandler, this);
+            }
+            // If both the screenshot and thumbnail fails, then just fall back to the default transition
+            return getUnknownTransitionActivityOptions();
+        }
+    }
 
-        // Update the destination rect
-        Task toTask = new Task();
-        TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                topTask.id, toTask);
-        Rect toTaskRect = toTransform.rect;
+    private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
+            TaskViewTransform toTransform) {
         Bitmap thumbnail;
         if (mThumbnailTransitionBitmapCacheKey != null
                 && mThumbnailTransitionBitmapCacheKey.key != null
@@ -546,15 +610,7 @@
             preloadIcon(topTask);
             thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
         }
-        if (thumbnail != null) {
-            mStartAnimationTriggered = false;
-            return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
-                    thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(),
-                    toTaskRect.height(), mHandler, this);
-        }
-
-        // If both the screenshot and thumbnail fails, then just fall back to the default transition
-        return getUnknownTransitionActivityOptions();
+        return thumbnail;
     }
 
     /**
@@ -621,7 +677,8 @@
      */
     private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
             boolean isTopTaskHome) {
-        RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        RecentsTaskLoader loader = Recents.getTaskLoader();
 
         // Update the header bar if necessary
         reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
@@ -638,7 +695,7 @@
 
         // Prepare the dummy stack for the transition
         mDummyStackView.updateMinMaxScrollForStack(stack);
-        TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
+        TaskStackLayoutAlgorithm.VisibilityReport stackVr =
                 mDummyStackView.computeStackVisibilityReport();
         boolean hasRecentTasks = stack.getTaskCount() > 0;
         boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
@@ -659,10 +716,10 @@
         if (!useThumbnailTransition) {
             // If there is no thumbnail transition, but is launching from home into recents, then
             // use a quick home transition and do the animation from home
-            if (hasRecentTasks) {
-                String homeActivityPackage = mSystemServicesProxy.getHomeActivityPackageName();
-                String searchWidgetPackage =
-                        Prefs.getString(mContext, Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
+            if (!Constants.DebugFlags.App.DisableSearchBar && hasRecentTasks) {
+                String homeActivityPackage = ssp.getHomeActivityPackageName();
+                String searchWidgetPackage = Prefs.getString(mContext,
+                        Prefs.Key.SEARCH_APP_WIDGET_PACKAGE, null);
 
                 // Determine whether we are coming from a search owned home activity
                 boolean fromSearchHome = (homeActivityPackage != null) &&
@@ -685,9 +742,12 @@
      */
     private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
               ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
-              TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+              TaskStackLayoutAlgorithm.VisibilityReport vr) {
+        mStartAnimationTriggered = false;
+
         // Update the configuration based on the launch options
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         launchState.launchedFromHome = fromSearchHome || fromHome;
         launchState.launchedFromSearchHome = fromSearchHome;
         launchState.launchedFromAppWithThumbnail = fromThumbnail;
@@ -697,6 +757,7 @@
         launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
         launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
         launchState.launchedHasConfigurationChanged = false;
+        launchState.startHidden = topTask != null && topTask.stackId == FREEFORM_WORKSPACE_STACK_ID;
 
         Intent intent = new Intent();
         intent.setClassName(RECENTS_PACKAGE, RECENTS_ACTIVITY);
@@ -718,7 +779,12 @@
         // Notify recents to start the enter animation
         if (!mStartAnimationTriggered) {
             mStartAnimationTriggered = true;
-            EventBus.getDefault().send(new EnterRecentsWindowAnimationStartedEvent());
+            EventBus.getDefault().post(new EnterRecentsWindowAnimationStartedEvent());
         }
     }
+
+    @Override
+    public void onAnimationFinished() {
+        EventBus.getDefault().post(new EnterRecentsWindowLastAnimationFrameEvent());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 7735ba9..28299d3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -30,7 +30,6 @@
 import android.widget.Toast;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.views.RecentsView;
 
@@ -80,7 +79,6 @@
     private View mResizeTaskDialogContent;
     private RecentsActivity mRecentsActivity;
     private RecentsView mRecentsView;
-    private SystemServicesProxy mSsp;
     private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
     private Task[] mTasks = {null, null, null, null};
 
@@ -93,7 +91,6 @@
     public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
         mFragmentManager = mgr;
         mRecentsActivity = activity;
-        mSsp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
     }
 
     /** Shows the resize-task dialog. */
@@ -144,7 +141,8 @@
 
     /** Helper function to place window(s) on the display according to an arrangement request. */
     private void placeTasks(int arrangement) {
-        Rect rect = mSsp.getDisplayRect();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect rect = ssp.getDisplayRect();
         for (int i = 0; i < mBounds.length; ++i) {
             mBounds[i].set(rect);
             if (i != 0) {
@@ -236,14 +234,6 @@
         dismissAllowingStateLoss();
         mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
 
-        // In debug mode, we force all task to be resizeable regardless of the
-        // current app configuration.
-        for (int i = additionalTasks; i >= 0; --i) {
-            if (mTasks[i] != null) {
-                mSsp.setTaskResizeable(mTasks[i].key.id);
-            }
-        }
-
         // Show tasks as they might not be currently visible - beginning with the oldest so that
         // the focus ends on the selected one.
         for (int i = additionalTasks; i >= 0; --i) {
@@ -278,8 +268,8 @@
 
         if (mTasks[0].key.stackId != DOCKED_STACK_ID) {
             int taskId = mTasks[0].key.id;
-            mSsp.setTaskResizeable(taskId);
-            mSsp.dockTask(taskId, createMode);
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.startTaskInDockedMode(taskId, createMode);
             mRecentsView.launchTask(mTasks[0], null, DOCKED_STACK_ID);
         } else {
             Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 231843e..10075bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -214,11 +214,8 @@
                         .setVisibility(View.INVISIBLE);
             }
 
-            final int description = mAccessibilityService.isEnabled()
-                    ? R.string.screen_pinning_description_accessible
-                    : R.string.screen_pinning_description;
             ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
-                    .setText(description);
+                    .setText(R.string.screen_pinning_description);
             final int backBgVisibility =
                     mAccessibilityService.isEnabled() ? View.INVISIBLE : View.VISIBLE;
             mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
index ef543d0..deae4c8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java
@@ -200,7 +200,8 @@
  */
 public class EventBus extends BroadcastReceiver {
 
-    public static final String TAG = "EventBus";
+    private static final String TAG = "EventBus";
+    private static final boolean DEBUG_TRACE_ALL = false;
 
     /**
      * An event super class that allows us to track internal event state across subscriber
@@ -208,7 +209,7 @@
      *
      * Events should not be edited by subscribers.
      */
-    public static class Event {
+    public static class Event implements Cloneable {
         // Indicates that this event's dispatch should be traced and logged to logcat
         boolean trace;
         // Indicates that this event must be posted on the EventBus's looper thread before invocation
@@ -218,6 +219,14 @@
 
         // Only accessible from derived events
         protected Event() {}
+
+        @Override
+        protected Object clone() throws CloneNotSupportedException {
+            Event evt = (Event) super.clone();
+            // When cloning an event, reset the cancelled-dispatch state
+            evt.cancelled = false;
+            return evt;
+        }
     }
 
     /**
@@ -269,9 +278,6 @@
     // The default priority of all subscribers
     private static final int DEFAULT_SUBSCRIBER_PRIORITY = 1;
 
-    // Used for debugging everything
-    private static final boolean DEBUG_TRACE_ALL = false;
-
     // Orders the handlers by priority and registration time
     private static final Comparator<EventHandler> EVENT_HANDLER_COMPARATOR = new Comparator<EventHandler>() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
similarity index 68%
rename from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
index 6769716..fd023d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowLastAnimationFrameEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,9 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.activity;
 
-/**
- * The String LRU cache.
- */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+import com.android.systemui.recents.events.EventBus;
+
+public class EnterRecentsWindowLastAnimationFrameEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
similarity index 61%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
index 6769716..f7b2706 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/IterateRecentsEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * The String LRU cache.
+ * This is sent when the user taps on the Overview button to iterate to the next item in the
+ * Recents list.
  */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+public class IterateRecentsEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
similarity index 89%
rename from packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
rename to packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
index 12e5d3d..968890a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java
@@ -23,12 +23,12 @@
 /**
  * This is sent when a {@link TaskView} has been dismissed.
  */
-public class DismissTaskEvent extends EventBus.Event {
+public class DismissTaskViewEvent extends EventBus.Event {
 
     public final Task task;
     public final TaskView taskView;
 
-    public DismissTaskEvent(Task task, TaskView taskView) {
+    public DismissTaskViewEvent(Task task, TaskView taskView) {
         this.task = task;
         this.taskView = taskView;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
index 6769716..6e6cd84 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/UserInteractionEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.ui;
+
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * The String LRU cache.
+ * This is sent whenever the user interacts with the activity.
  */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+public class UserInteractionEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
index 6769716..9f3e9d5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * The String LRU cache.
+ * Dismisses the currently focused task view.
  */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+public class DismissFocusedTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
similarity index 66%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
index 6769716..171ab5e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusNextTaskViewEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * The String LRU cache.
+ * Focuses the next task view in the stack.
  */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+public class FocusNextTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
similarity index 65%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
index 6769716..22469e7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/FocusPreviousTaskViewEvent.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+package com.android.systemui.recents.events.ui.focus;
+
+import com.android.systemui.recents.events.EventBus;
 
 /**
- * The String LRU cache.
+ * Focuses the previous task view in the stack.
  */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+public class FocusPreviousTaskViewEvent extends EventBus.Event {
+    // Simple event
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
index 735f79f..336d2db 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
@@ -19,8 +19,8 @@
 import android.os.Handler;
 
 /**
- * A dozer is a class that fires a trigger after it falls asleep.  You can occasionally poke it to
- * wake it up, but it will fall asleep if left untouched.
+ * A dozer is a class that fires a trigger after it falls asleep.
+ * You can occasionally poke the trigger to wake it up, but it will fall asleep if left untouched.
  */
 public class DozeTrigger {
 
@@ -28,7 +28,7 @@
 
     boolean mIsDozing;
     boolean mHasTriggered;
-    int mDozeDurationSeconds;
+    int mDozeDurationMilliseconds;
     Runnable mSleepRunnable;
 
     // Sleep-runnable
@@ -41,9 +41,9 @@
         }
     };
 
-    public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) {
+    public DozeTrigger(int dozeDurationMilliseconds, Runnable sleepRunnable) {
         mHandler = new Handler();
-        mDozeDurationSeconds = dozeDurationSeconds;
+        mDozeDurationMilliseconds = dozeDurationMilliseconds;
         mSleepRunnable = sleepRunnable;
     }
 
@@ -69,7 +69,7 @@
     /** Poke this dozer to wake it up for a little bit. */
     void forcePoke() {
         mHandler.removeCallbacks(mDozeRunnable);
-        mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000);
+        mHandler.postDelayed(mDozeRunnable, mDozeDurationMilliseconds);
         mIsDozing = true;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java
new file mode 100644
index 0000000..8dc2983
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ForegroundThread.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.misc;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+
+/**
+ * Similar to {@link com.android.internal.os.BackgroundThread}, this is a shared singleton
+ * foreground thread for each process.
+ */
+public final class ForegroundThread extends HandlerThread {
+    private static ForegroundThread sInstance;
+    private static Handler sHandler;
+
+    private ForegroundThread() {
+        super("recents.fg", android.os.Process.THREAD_PRIORITY_BACKGROUND);
+    }
+
+    private static void ensureThreadLocked() {
+        if (sInstance == null) {
+            sInstance = new ForegroundThread();
+            sInstance.start();
+            sHandler = new Handler(sInstance.getLooper());
+        }
+    }
+
+    public static ForegroundThread get() {
+        synchronized (ForegroundThread.class) {
+            ensureThreadLocked();
+            return sInstance;
+        }
+    }
+
+    public static Handler getHandler() {
+        synchronized (ForegroundThread.class) {
+            ensureThreadLocked();
+            return sHandler;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
index 8e85bfc..ea6821f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ParametricCurve.java
@@ -48,6 +48,7 @@
 
     float[] xp;
     float[] px;
+    float mLength;
 
     CurveFunction mFn;
     ParametricCurveFunction mScaleFn;
@@ -79,6 +80,7 @@
             dx[xStep] = (float) Math.hypot(fx[xStep] - fx[xStep - 1], step);
             pLength += dx[xStep];
         }
+        mLength = pLength;
         // Approximate p(x), a function of cumulative progress with x, normalized to 0..1
         float p = 0;
         px[0] = 0f;
@@ -260,4 +262,11 @@
         }
         return 1f - xToP(maxX, bounds);
     }
+
+    /**
+     * Returns the length of this curve.
+     */
+    public float getArcLength() {
+        return mLength;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index dab2c65..141562c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -46,8 +46,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.os.SystemProperties;
@@ -61,6 +59,7 @@
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
 import com.android.internal.app.AssistUtils;
+import com.android.internal.os.BackgroundThread;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
@@ -83,12 +82,8 @@
     final static String TAG = "SystemServicesProxy";
 
     final static BitmapFactory.Options sBitmapOptions;
-    final static HandlerThread sBgThread;
 
     static {
-        sBgThread = new HandlerThread("Recents-SystemServicesProxy",
-                android.os.Process.THREAD_PRIORITY_BACKGROUND);
-        sBgThread.start();
         sBitmapOptions = new BitmapFactory.Options();
         sBitmapOptions.inMutable = true;
     }
@@ -106,8 +101,6 @@
     String mRecentsPackage;
     ComponentName mAssistComponent;
 
-    Handler mBgThreadHandler;
-
     Bitmap mDummyIcon;
     int mDummyThumbnailWidth;
     int mDummyThumbnailHeight;
@@ -127,7 +120,6 @@
         mUm = UserManager.get(context);
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
-        mBgThreadHandler = new Handler(sBgThread.getLooper());
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -255,8 +247,10 @@
                 return true;
             }
 
+            // Note, this is only valid because we currently only allow the recents and home
+            // activities in the home stack
             if (isHomeTopMost != null) {
-                isHomeTopMost.value = isInHomeStack(topTask.id);
+                isHomeTopMost.value = SystemServicesProxy.isHomeStack(topTask.stackId);
             }
         }
         return false;
@@ -274,17 +268,6 @@
         return null;
     }
 
-    /** Allow a task to resize. */
-    public void setTaskResizeable(int taskId) {
-        if (mIam == null) return;
-
-        try {
-            mIam.setTaskResizeable(taskId, true);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-    }
-
     /**
      * Resizes the given task to the new bounds.
      */
@@ -298,12 +281,14 @@
         }
     }
 
-    /** Docks a task to the side of the screen. */
-    public void dockTask(int taskId, int createMode) {
+    /** Docks a task to the side of the screen and starts it. */
+    public void startTaskInDockedMode(int taskId, int createMode) {
         if (mIam == null) return;
 
         try {
-            mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, null);
+            final ActivityOptions options = ActivityOptions.makeBasic();
+            options.setDockCreateMode(createMode);
+            mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle());
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -321,16 +306,18 @@
         }
     }
 
-    /** Returns whether the specified task is in the home stack */
-    public boolean isInHomeStack(int taskId) {
-        if (mAm == null) return false;
+    /**
+     * Returns whether the given stack id is the home stack id.
+     */
+    public static boolean isHomeStack(int stackId) {
+        return stackId == ActivityManager.HOME_STACK_ID;
+    }
 
-        // If we are mocking, then just return false
-        if (Constants.DebugFlags.App.EnableSystemServicesProxy) {
-            return false;
-        }
-
-        return mAm.isInHomeStack(taskId);
+    /**
+     * Returns whether the given stack id is the freeform workspace stack id.
+     */
+    public static boolean isFreeformStack(int stackId) {
+        return stackId == ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
     }
 
     /**
@@ -418,7 +405,7 @@
         if (Constants.DebugFlags.App.EnableSystemServicesProxy) return;
 
         // Remove the task.
-        mBgThreadHandler.post(new Runnable() {
+        BackgroundThread.getHandler().post(new Runnable() {
             @Override
             public void run() {
                 mAm.removeTask(taskId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 93c5ee7..2bf2ccb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,13 +18,10 @@
 
 import android.animation.Animator;
 import android.graphics.Color;
-import android.graphics.Matrix;
-import android.graphics.Rect;
+import android.graphics.RectF;
 import android.view.View;
 import android.view.ViewParent;
 
-import java.util.ArrayList;
-
 /* Common code */
 public class Utilities {
 
@@ -45,93 +42,19 @@
     }
 
     /** Scales a rect about its centroid */
-    public static void scaleRectAboutCenter(Rect r, float scale) {
+    public static void scaleRectAboutCenter(RectF r, float scale) {
         if (scale != 1.0f) {
-            int cx = r.centerX();
-            int cy = r.centerY();
+            float cx = r.centerX();
+            float cy = r.centerY();
             r.offset(-cx, -cy);
-            r.left = (int) (r.left * scale + 0.5f);
-            r.top = (int) (r.top * scale + 0.5f);
-            r.right = (int) (r.right * scale + 0.5f);
-            r.bottom = (int) (r.bottom * scale + 0.5f);
+            r.left *= scale;
+            r.top *= scale;
+            r.right *= scale;
+            r.bottom *= scale;
             r.offset(cx, cy);
         }
     }
 
-    /** Maps a coorindate in a descendant view into the parent. */
-    public static float mapCoordInDescendentToSelf(View descendant, View root,
-            float[] coord, boolean includeRootScroll) {
-        ArrayList<View> ancestorChain = new ArrayList<View>();
-
-        float[] pt = {coord[0], coord[1]};
-
-        View v = descendant;
-        while(v != root && v != null) {
-            ancestorChain.add(v);
-            v = (View) v.getParent();
-        }
-        ancestorChain.add(root);
-
-        float scale = 1.0f;
-        int count = ancestorChain.size();
-        for (int i = 0; i < count; i++) {
-            View v0 = ancestorChain.get(i);
-            // For TextViews, scroll has a meaning which relates to the text position
-            // which is very strange... ignore the scroll.
-            if (v0 != descendant || includeRootScroll) {
-                pt[0] -= v0.getScrollX();
-                pt[1] -= v0.getScrollY();
-            }
-
-            v0.getMatrix().mapPoints(pt);
-            pt[0] += v0.getLeft();
-            pt[1] += v0.getTop();
-            scale *= v0.getScaleX();
-        }
-
-        coord[0] = pt[0];
-        coord[1] = pt[1];
-        return scale;
-    }
-
-    /** Maps a coordinate in the root to a descendent. */
-    public static float mapCoordInSelfToDescendent(View descendant, View root,
-            float[] coord, Matrix tmpInverseMatrix) {
-        ArrayList<View> ancestorChain = new ArrayList<View>();
-
-        float[] pt = {coord[0], coord[1]};
-
-        View v = descendant;
-        while(v != root) {
-            ancestorChain.add(v);
-            v = (View) v.getParent();
-        }
-        ancestorChain.add(root);
-
-        float scale = 1.0f;
-        int count = ancestorChain.size();
-        tmpInverseMatrix.set(Matrix.IDENTITY_MATRIX);
-        for (int i = count - 1; i >= 0; i--) {
-            View ancestor = ancestorChain.get(i);
-            View next = i > 0 ? ancestorChain.get(i-1) : null;
-
-            pt[0] += ancestor.getScrollX();
-            pt[1] += ancestor.getScrollY();
-
-            if (next != null) {
-                pt[0] -= next.getLeft();
-                pt[1] -= next.getTop();
-                next.getMatrix().invert(tmpInverseMatrix);
-                tmpInverseMatrix.mapPoints(pt);
-                scale *= next.getScaleX();
-            }
-        }
-
-        coord[0] = pt[0];
-        coord[1] = pt[1];
-        return scale;
-    }
-
     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
     public static float computeContrastBetweenColors(int bg, int fg) {
         float bgR = Color.red(bg) / 255f;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java
deleted file mode 100644
index 624a8ff..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/BitmapLruCache.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.graphics.Bitmap;
-
-/**
- * The Bitmap LRU cache.
- */
-class BitmapLruCache extends KeyStoreLruCache<Bitmap> {
-    public BitmapLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java
deleted file mode 100644
index 01a515b..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/DrawableLruCache.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.graphics.drawable.Drawable;
-
-/**
- * The Drawable LRU cache.
- */
-class DrawableLruCache extends KeyStoreLruCache<Drawable> {
-    public DrawableLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
deleted file mode 100644
index 97e0916..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.model;
-
-import android.util.LruCache;
-
-import java.util.HashMap;
-
-/**
- * An LRU cache that internally support querying the keys as well as values.  We use this to keep
- * track of the task metadata to determine when to invalidate the cache when tasks have been
- * updated. Generally, this cache will return the last known cache value for the requested task
- * key.
- */
-public class KeyStoreLruCache<V> {
-    // We keep a set of keys that are associated with the LRU cache, so that we can find out
-    // information about the Task that was previously in the cache.
-    HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>();
-    // The cache implementation, mapping task id -> value
-    LruCache<Integer, V> mCache;
-
-    public KeyStoreLruCache(int cacheSize) {
-        mCache = new LruCache<Integer, V>(cacheSize) {
-
-            @Override
-            protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
-                mTaskKeys.remove(taskId);
-            }
-        };
-    }
-
-    /** Gets a specific entry in the cache. */
-    final V get(Task.TaskKey key) {
-        return mCache.get(key.id);
-    }
-
-    /**
-     * Returns the value only if the Task has not updated since the last time it was in the cache.
-     */
-    final V getAndInvalidateIfModified(Task.TaskKey key) {
-        Task.TaskKey lastKey = mTaskKeys.get(key.id);
-        if (lastKey != null && (lastKey.lastActiveTime < key.lastActiveTime)) {
-            // The task has updated (been made active since the last time it was put into the
-            // LRU cache) so invalidate that item in the cache
-            remove(key);
-            return null;
-        }
-        // Either the task does not exist in the cache, or the last active time is the same as
-        // the key specified, so return what is in the cache
-        return mCache.get(key.id);
-    }
-
-    /** Puts an entry in the cache for a specific key. */
-    final void put(Task.TaskKey key, V value) {
-        mCache.put(key.id, value);
-        mTaskKeys.put(key.id, key);
-    }
-
-    /** Removes a cache entry for a specific key. */
-    final void remove(Task.TaskKey key) {
-        mCache.remove(key.id);
-        mTaskKeys.remove(key.id);
-    }
-
-    /** Removes all the entries in the cache. */
-    final void evictAll() {
-        mCache.evictAll();
-        mTaskKeys.clear();
-    }
-
-    /** Returns the size of the cache. */
-    final int size() {
-        return mCache.size();
-    }
-
-    /** Trims the cache to a specific size */
-    final void trimToSize(int cacheSize) {
-        mCache.resize(cacheSize);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
index 8f9a293..d9057b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java
@@ -16,17 +16,12 @@
 
 package com.android.systemui.recents.model;
 
-import android.content.ComponentName;
 import android.content.Context;
-import android.os.Looper;
 import android.os.UserHandle;
 import com.android.internal.content.PackageMonitor;
+import com.android.internal.os.BackgroundThread;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-
-import java.util.HashSet;
-import java.util.List;
 
 /**
  * The package monitor listens for changes from PackageManager to update the contents of the
@@ -38,8 +33,9 @@
     public void register(Context context) {
         try {
             // We register for events from all users, but will cross-reference them with
-            // packages for the current user and any profiles they have
-            register(context, Looper.getMainLooper(), UserHandle.ALL, true);
+            // packages for the current user and any profiles they have.  Ensure that events are
+            // handled in a background thread.
+            register(context, BackgroundThread.get().getLooper(), UserHandle.ALL, true);
         } catch (IllegalStateException e) {
             e.printStackTrace();
         }
@@ -57,9 +53,9 @@
 
     @Override
     public void onPackageRemoved(String packageName, int uid) {
-        // Notify callbacks that a package has changed
+        // Notify callbacks on the main thread that a package has changed
         final int eventUserId = getChangingUserId();
-        EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
+        EventBus.getDefault().post(new PackagesChangedEvent(this, packageName, eventUserId));
     }
 
     @Override
@@ -70,39 +66,8 @@
 
     @Override
     public void onPackageModified(String packageName) {
-        // Notify callbacks that a package has changed
+        // Notify callbacks on the main thread that a package has changed
         final int eventUserId = getChangingUserId();
-        EventBus.getDefault().send(new PackagesChangedEvent(this, packageName, eventUserId));
-    }
-
-    /**
-     * Computes the components that have been removed as a result of a change in the specified
-     * package.
-     */
-    public HashSet<ComponentName> computeComponentsRemoved(List<Task.TaskKey> taskKeys,
-            String packageName, int userId) {
-        // Identify all the tasks that should be removed as a result of the package being removed.
-        // Using a set to ensure that we callback once per unique component.
-        HashSet<ComponentName> existingComponents = new HashSet<ComponentName>();
-        HashSet<ComponentName> removedComponents = new HashSet<ComponentName>();
-        for (Task.TaskKey t : taskKeys) {
-            // Skip if this doesn't apply to the current user
-            if (t.userId != userId) continue;
-
-            ComponentName cn = t.baseIntent.getComponent();
-            if (cn.getPackageName().equals(packageName)) {
-                if (existingComponents.contains(cn)) {
-                    // If we know that the component still exists in the package, then skip
-                    continue;
-                }
-                SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-                if (ssp.getActivityInfo(cn, userId) != null) {
-                    existingComponents.add(cn);
-                } else {
-                    removedComponents.add(cn);
-                }
-            }
-        }
-        return removedComponents;
+        EventBus.getDefault().post(new PackagesChangedEvent(this, packageName, eventUserId));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 6ef7253..6c83b87 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -23,12 +23,12 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.Log;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.List;
 
 
@@ -41,8 +41,11 @@
  *      options specified, such that we can transition into the Recents activity seamlessly
  */
 public class RecentsTaskLoadPlan {
-    static String TAG = "RecentsTaskLoadPlan";
-    static boolean DEBUG = false;
+
+    private static String TAG = "RecentsTaskLoadPlan";
+    private static boolean DEBUG = false;
+
+    private static int INVALID_TASK_ID = -1;
 
     /** The set of conditions to load tasks. */
     public static class Options {
@@ -56,44 +59,50 @@
     }
 
     Context mContext;
-    RecentsConfiguration mConfig;
-    SystemServicesProxy mSystemServicesProxy;
 
     List<ActivityManager.RecentTaskInfo> mRawTasks;
     TaskStack mStack;
-    HashMap<Task.ComponentNameKey, ActivityInfoHandle> mActivityInfoCache =
-            new HashMap<Task.ComponentNameKey, ActivityInfoHandle>();
 
     /** Package level ctor */
-    RecentsTaskLoadPlan(Context context, RecentsConfiguration config, SystemServicesProxy ssp) {
+    RecentsTaskLoadPlan(Context context) {
         mContext = context;
-        mConfig = config;
-        mSystemServicesProxy = ssp;
     }
 
     /**
-     * An optimization to preload the raw list of tasks.
+     * An optimization to preload the raw list of tasks.  The raw tasks are saved in least-recent
+     * to most-recent order.
      */
     public synchronized void preloadRawTasks(boolean isTopTaskHome) {
-        mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 UserHandle.CURRENT.getIdentifier(), isTopTaskHome);
+        // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
         Collections.reverse(mRawTasks);
 
-        if (DEBUG) Log.d(TAG, "preloadRawTasks, tasks: " + mRawTasks.size());
+        if (DEBUG) {
+            Log.d(TAG, "preloadRawTasks, tasks: " + mRawTasks.size());
+            for (ActivityManager.RecentTaskInfo info : mRawTasks) {
+                Log.d(TAG, "  " + info.baseIntent + ", " + info.lastActiveTime);
+            }
+        }
     }
 
     /**
      * Preloads the list of recent tasks from the system.  After this call, the TaskStack will
      * have a list of all the recent tasks with their metadata, not including icons or
      * thumbnails which were not cached and have to be loaded.
+     *
+     * The tasks will be ordered by:
+     * - least-recent to most-recent stack tasks
+     * - least-recent to most-recent freeform tasks
      */
-    synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
+    public synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) {
         if (DEBUG) Log.d(TAG, "preloadPlan");
 
-        // This activity info cache will be used for both preloadPlan() and executePlan()
-        mActivityInfoCache.clear();
-
+        RecentsConfiguration config = Recents.getConfiguration();
+        SystemServicesProxy ssp = Recents.getSystemServices();
         Resources res = mContext.getResources();
+        ArrayList<Task> freeformTasks = new ArrayList<>();
         ArrayList<Task> stackTasks = new ArrayList<>();
         if (mRawTasks == null) {
             preloadRawTasks(isTopTaskHome);
@@ -106,64 +115,55 @@
             Task.TaskKey taskKey = new Task.TaskKey(t.persistentId, t.stackId, t.baseIntent,
                     t.userId, t.firstActiveTime, t.lastActiveTime);
 
-            // Get an existing activity info handle if possible
-            Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
-            ActivityInfoHandle infoHandle;
-            boolean hadCachedActivityInfo = false;
-            if (mActivityInfoCache.containsKey(cnKey)) {
-                infoHandle = mActivityInfoCache.get(cnKey);
-                hadCachedActivityInfo = true;
-            } else {
-                infoHandle = new ActivityInfoHandle();
-            }
-
             // Load the label, icon, and color
             String activityLabel = loader.getAndUpdateActivityLabel(taskKey, t.taskDescription,
-                    mSystemServicesProxy, infoHandle);
+                    ssp);
             String contentDescription = loader.getAndUpdateContentDescription(taskKey,
-                    activityLabel, mSystemServicesProxy, res);
-            Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
-                    mSystemServicesProxy, res, infoHandle, false);
-            int activityColor = loader.getActivityPrimaryColor(t.taskDescription, res);
-
-            // Update the activity info cache
-            if (!hadCachedActivityInfo && infoHandle.info != null) {
-                mActivityInfoCache.put(cnKey, infoHandle);
-            }
+                    activityLabel, ssp, res);
+            Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, ssp,
+                    res, false);
+            int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
 
             Bitmap icon = t.taskDescription != null
-                    ? t.taskDescription.getInMemoryIcon()
-                    : null;
+                    ? t.taskDescription.getInMemoryIcon() : null;
             String iconFilename = t.taskDescription != null
-                    ? t.taskDescription.getIconFilename()
-                    : null;
+                    ? t.taskDescription.getIconFilename() : null;
 
             // Add the task to the stack
-            Task task = new Task(taskKey, (t.id != RecentsTaskLoader.INVALID_TASK_ID),
-                    t.affiliatedTaskId, t.affiliatedTaskColor, activityLabel, contentDescription,
-                    activityIcon, activityColor, (i == (taskCount - 1)), mConfig.lockToAppEnabled,
-                    icon, iconFilename);
-            task.thumbnail = loader.getAndUpdateThumbnail(taskKey, mSystemServicesProxy, false);
+            Task task = new Task(taskKey, (t.id != INVALID_TASK_ID), t.affiliatedTaskId,
+                    t.affiliatedTaskColor, activityLabel, contentDescription, activityIcon,
+                    activityColor, (i == (taskCount - 1)), config.lockToAppEnabled, icon,
+                    iconFilename);
+            task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, false);
             if (DEBUG) Log.d(TAG, "\tthumbnail: " + taskKey + ", " + task.thumbnail);
 
-            stackTasks.add(task);
+            if (task.isFreeformTask()) {
+                freeformTasks.add(task);
+            } else {
+                stackTasks.add(task);
+            }
         }
 
         // Initialize the stacks
+        ArrayList<Task> allTasks = new ArrayList<>();
+        allTasks.addAll(stackTasks);
+        allTasks.addAll(freeformTasks);
         mStack = new TaskStack();
-        mStack.setTasks(stackTasks);
+        mStack.setTasks(allTasks);
         mStack.createAffiliatedGroupings(mContext);
     }
 
     /**
      * Called to apply the actual loading based on the specified conditions.
      */
-    synchronized void executePlan(Options opts, RecentsTaskLoader loader,
+    public synchronized void executePlan(Options opts, RecentsTaskLoader loader,
             TaskResourceLoadQueue loadQueue) {
         if (DEBUG) Log.d(TAG, "executePlan, # tasks: " + opts.numVisibleTasks +
                 ", # thumbnails: " + opts.numVisibleTaskThumbnails +
                 ", running task id: " + opts.runningTaskId);
 
+        RecentsConfiguration config = Recents.getConfiguration();
+        SystemServicesProxy ssp = Recents.getSystemServices();
         Resources res = mContext.getResources();
 
         // Iterate through each of the tasks and load them according to the load conditions.
@@ -174,17 +174,6 @@
             Task task = tasks.get(i);
             Task.TaskKey taskKey = task.key;
 
-            // Get an existing activity info handle if possible
-            Task.ComponentNameKey cnKey = taskKey.getComponentNameKey();
-            ActivityInfoHandle infoHandle;
-            boolean hadCachedActivityInfo = false;
-            if (mActivityInfoCache.containsKey(cnKey)) {
-                infoHandle = mActivityInfoCache.get(cnKey);
-                hadCachedActivityInfo = true;
-            } else {
-                infoHandle = new ActivityInfoHandle();
-            }
-
             boolean isRunningTask = (task.key.id == opts.runningTaskId);
             boolean isVisibleTask = i >= (taskCount - opts.numVisibleTasks);
             boolean isVisibleThumbnail = i >= (taskCount - opts.numVisibleTaskThumbnails);
@@ -197,26 +186,20 @@
             if (opts.loadIcons && (isRunningTask || isVisibleTask)) {
                 if (task.activityIcon == null) {
                     if (DEBUG) Log.d(TAG, "\tLoading icon: " + taskKey);
-                    task.activityIcon = loader.getAndUpdateActivityIcon(taskKey,
-                            t.taskDescription, mSystemServicesProxy, res, infoHandle, true);
+                    task.activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
+                            ssp, res, true);
                 }
             }
             if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
                 if (task.thumbnail == null || isRunningTask) {
                     if (DEBUG) Log.d(TAG, "\tLoading thumbnail: " + taskKey);
-                    if (mConfig.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
-                                mSystemServicesProxy, true);
-                    } else if (mConfig.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
+                    if (config.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
+                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, ssp, true);
+                    } else if (config.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
                         loadQueue.addTask(task);
                     }
                 }
             }
-
-            // Update the activity info cache
-            if (!hadCachedActivityInfo && infoHandle.info != null) {
-                mActivityInfoCache.put(cnKey, infoHandle);
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 39bef81..71e3957 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -18,6 +18,7 @@
 
 import android.app.ActivityManager;
 import android.content.ComponentCallbacks2;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Resources;
@@ -27,20 +28,21 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
+import android.util.LruCache;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
+import java.util.Map;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
 
-/** Handle to an ActivityInfo */
-class ActivityInfoHandle {
-    ActivityInfo info;
-}
-
-/** A bitmap load queue */
+/**
+ * A Task load queue
+ */
 class TaskResourceLoadQueue {
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
 
@@ -78,8 +80,10 @@
     }
 }
 
-/* Task resource loader */
-class TaskResourceLoader implements Runnable {
+/**
+ * Task resource loader
+ */
+class BackgroundTaskLoader implements Runnable {
     static String TAG = "TaskResourceLoader";
     static boolean DEBUG = false;
 
@@ -88,10 +92,9 @@
     Handler mLoadThreadHandler;
     Handler mMainThreadHandler;
 
-    SystemServicesProxy mSystemServicesProxy;
     TaskResourceLoadQueue mLoadQueue;
-    DrawableLruCache mApplicationIconCache;
-    BitmapLruCache mThumbnailCache;
+    TaskKeyLruCache<Drawable> mApplicationIconCache;
+    TaskKeyLruCache<Bitmap> mThumbnailCache;
     Bitmap mDefaultThumbnail;
     BitmapDrawable mDefaultApplicationIcon;
 
@@ -99,9 +102,9 @@
     boolean mWaitingOnLoadQueue;
 
     /** Constructor, creates a new loading thread that loads task resources in the background */
-    public TaskResourceLoader(TaskResourceLoadQueue loadQueue, DrawableLruCache applicationIconCache,
-                              BitmapLruCache thumbnailCache, Bitmap defaultThumbnail,
-                              BitmapDrawable defaultApplicationIcon) {
+    public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
+            TaskKeyLruCache<Drawable> applicationIconCache, TaskKeyLruCache<Bitmap> thumbnailCache,
+            Bitmap defaultThumbnail, BitmapDrawable defaultApplicationIcon) {
         mLoadQueue = loadQueue;
         mApplicationIconCache = applicationIconCache;
         mThumbnailCache = thumbnailCache;
@@ -119,7 +122,6 @@
     void start(Context context) {
         mContext = context;
         mCancelled = false;
-        mSystemServicesProxy = new SystemServicesProxy(context);
         // Notify the load thread to start loading
         synchronized(mLoadThread) {
             mLoadThread.notifyAll();
@@ -130,7 +132,6 @@
     void stop() {
         // Mark as cancelled for the thread to pick up
         mCancelled = true;
-        mSystemServicesProxy = null;
         // If we are waiting for the load queue for more tasks, then we can just reset the
         // Context now, since nothing is using it
         if (mWaitingOnLoadQueue) {
@@ -154,8 +155,8 @@
                     }
                 }
             } else {
-                RecentsConfiguration config = RecentsConfiguration.getInstance();
-                SystemServicesProxy ssp = mSystemServicesProxy;
+                RecentsConfiguration config = Recents.getConfiguration();
+                SystemServicesProxy ssp = Recents.getSystemServices();
                 // If we've stopped the loader, then fall through to the above logic to wait on
                 // the load thread
                 if (ssp != null) {
@@ -172,7 +173,7 @@
 
                             if (cachedIcon == null) {
                                 ActivityInfo info = ssp.getActivityInfo(
-                                        t.key.baseIntent.getComponent(), t.key.userId);
+                                        t.key.getComponent(), t.key.userId);
                                 if (info != null) {
                                     if (DEBUG) Log.d(TAG, "Loading icon: " + t.key);
                                     cachedIcon = ssp.getActivityIcon(info, t.key.userId);
@@ -246,201 +247,67 @@
     }
 }
 
-/* Recents task loader
- * NOTE: We should not hold any references to non-application Context from a static instance */
+/**
+ * Recents task loader
+ */
 public class RecentsTaskLoader {
+
     private static final String TAG = "RecentsTaskLoader";
+    private static final boolean DEBUG = false;
 
-    static RecentsTaskLoader sInstance;
-    static int INVALID_TASK_ID = -1;
+    // This activity info LruCache is useful because it can be expensive to retrieve ActivityInfos
+    // for many tasks, which we use to get the activity labels and icons.  Unlike the other caches
+    // below, this is per-package so we can't invalidate the items in the cache based on the last
+    // active time.  Instead, we rely on the RecentsPackageMonitor to keep us informed whenever a
+    // package in the cache has been updated, so that we may remove it.
+    private final LruCache<ComponentName, ActivityInfo> mActivityInfoCache;
+    private final TaskKeyLruCache<Drawable> mApplicationIconCache;
+    private final TaskKeyLruCache<Bitmap> mThumbnailCache;
+    private final TaskKeyLruCache<String> mActivityLabelCache;
+    private final TaskKeyLruCache<String> mContentDescriptionCache;
+    private final TaskResourceLoadQueue mLoadQueue;
+    private final BackgroundTaskLoader mLoader;
 
-    SystemServicesProxy mSystemServicesProxy;
-    DrawableLruCache mApplicationIconCache;
-    BitmapLruCache mThumbnailCache;
-    StringLruCache mActivityLabelCache;
-    StringLruCache mContentDescriptionCache;
-    TaskResourceLoadQueue mLoadQueue;
-    TaskResourceLoader mLoader;
+    private final int mMaxThumbnailCacheSize;
+    private final int mMaxIconCacheSize;
+    private int mNumVisibleTasksLoaded;
+    private int mNumVisibleThumbnailsLoaded;
 
-    int mMaxThumbnailCacheSize;
-    int mMaxIconCacheSize;
-    int mNumVisibleTasksLoaded;
-    int mNumVisibleThumbnailsLoaded;
-
+    int mDefaultTaskBarBackgroundColor;
     BitmapDrawable mDefaultApplicationIcon;
     Bitmap mDefaultThumbnail;
 
-    /** Private Constructor */
-    private RecentsTaskLoader(Context context) {
-        mMaxThumbnailCacheSize = context.getResources().getInteger(
-                R.integer.config_recents_max_thumbnail_count);
-        mMaxIconCacheSize = context.getResources().getInteger(
-                R.integer.config_recents_max_icon_count);
+    public RecentsTaskLoader(Context context) {
+        Resources res = context.getResources();
+        mDefaultTaskBarBackgroundColor =
+                res.getColor(R.color.recents_task_bar_default_background_color);
+        mMaxThumbnailCacheSize = res.getInteger(R.integer.config_recents_max_thumbnail_count);
+        mMaxIconCacheSize = res.getInteger(R.integer.config_recents_max_icon_count);
         int iconCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxIconCacheSize;
         int thumbnailCacheSize = Constants.DebugFlags.App.DisableBackgroundCache ? 1 :
                 mMaxThumbnailCacheSize;
 
         // Create the default assets
-        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
-        icon.eraseColor(0x00000000);
+        Bitmap icon = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
+        icon.eraseColor(0);
         mDefaultThumbnail = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         mDefaultThumbnail.setHasAlpha(false);
         mDefaultThumbnail.eraseColor(0xFFffffff);
         mDefaultApplicationIcon = new BitmapDrawable(context.getResources(), icon);
 
         // Initialize the proxy, cache and loaders
-        mSystemServicesProxy = new SystemServicesProxy(context);
+        int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
         mLoadQueue = new TaskResourceLoadQueue();
-        mApplicationIconCache = new DrawableLruCache(iconCacheSize);
-        mThumbnailCache = new BitmapLruCache(thumbnailCacheSize);
-        mActivityLabelCache = new StringLruCache(100);
-        mContentDescriptionCache = new StringLruCache(100);
-        mLoader = new TaskResourceLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
+        mApplicationIconCache = new TaskKeyLruCache<>(iconCacheSize);
+        mThumbnailCache = new TaskKeyLruCache<>(thumbnailCacheSize);
+        mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks);
+        mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks);
+        mActivityInfoCache = new LruCache(numRecentTasks);
+        mLoader = new BackgroundTaskLoader(mLoadQueue, mApplicationIconCache, mThumbnailCache,
                 mDefaultThumbnail, mDefaultApplicationIcon);
     }
 
-    /** Initializes the recents task loader */
-    public static RecentsTaskLoader initialize(Context context) {
-        if (sInstance == null) {
-            sInstance = new RecentsTaskLoader(context);
-        }
-        return sInstance;
-    }
-
-    /** Returns the current recents task loader */
-    public static RecentsTaskLoader getInstance() {
-        return sInstance;
-    }
-
-    /** Returns the system services proxy */
-    public SystemServicesProxy getSystemServicesProxy() {
-        return mSystemServicesProxy;
-    }
-
-    /** Returns the activity label using as many cached values as we can. */
-    public String getAndUpdateActivityLabel(Task.TaskKey taskKey,
-            ActivityManager.TaskDescription td, SystemServicesProxy ssp,
-            ActivityInfoHandle infoHandle) {
-        // Return the task description label if it exists
-        if (td != null && td.getLabel() != null) {
-            return td.getLabel();
-        }
-        // Return the cached activity label if it exists
-        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
-        if (label != null) {
-            return label;
-        }
-        // All short paths failed, load the label from the activity info and cache it
-        if (infoHandle.info == null) {
-            infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
-                    taskKey.userId);
-        }
-        if (infoHandle.info != null) {
-            label = ssp.getActivityLabel(infoHandle.info);
-            mActivityLabelCache.put(taskKey, label);
-            return label;
-        } else {
-            Log.w(TAG, "Missing ActivityInfo for " + taskKey.baseIntent.getComponent()
-                    + " u=" + taskKey.userId);
-        }
-        // If the activity info does not exist or fails to load, return an empty label for now,
-        // but do not cache it
-        return "";
-    }
-
-    /** Returns the content description using as many cached values as we can. */
-    public String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
-            SystemServicesProxy ssp, Resources res) {
-        // Return the cached content description if it exists
-        String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
-        if (label != null) {
-            return label;
-        }
-        // If the given activity label is empty, don't compute or cache the content description
-        if (activityLabel.isEmpty()) {
-            return "";
-        }
-
-        label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
-        if (label != null) {
-            mContentDescriptionCache.put(taskKey, label);
-            return label;
-        } else {
-            Log.w(TAG, "Missing content description for " + taskKey.baseIntent.getComponent()
-                    + " u=" + taskKey.userId);
-        }
-        // If the content description does not exist, return an empty label for now, but do not
-        // cache it
-        return "";
-    }
-
-    /** Returns the activity icon using as many cached values as we can. */
-    public Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey,
-            ActivityManager.TaskDescription td, SystemServicesProxy ssp,
-            Resources res, ActivityInfoHandle infoHandle, boolean loadIfNotCached) {
-        // Return the cached activity icon if it exists
-        Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
-        if (icon != null) {
-            return icon;
-        }
-
-        if (loadIfNotCached) {
-            // Return and cache the task description icon if it exists
-            Drawable tdDrawable = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
-                    td.getIconFilename(), ssp, res);
-            if (tdDrawable != null) {
-                mApplicationIconCache.put(taskKey, tdDrawable);
-                return tdDrawable;
-            }
-
-            // Load the icon from the activity info and cache it
-            if (infoHandle.info == null) {
-                infoHandle.info = ssp.getActivityInfo(taskKey.baseIntent.getComponent(),
-                        taskKey.userId);
-            }
-            if (infoHandle.info != null) {
-                icon = ssp.getActivityIcon(infoHandle.info, taskKey.userId);
-                if (icon != null) {
-                    mApplicationIconCache.put(taskKey, icon);
-                    return icon;
-                }
-            }
-        }
-        // We couldn't load any icon
-        return null;
-    }
-
-    /** Returns the bitmap using as many cached values as we can. */
-    public Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, SystemServicesProxy ssp,
-            boolean loadIfNotCached) {
-        // Return the cached thumbnail if it exists
-        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
-        if (thumbnail != null) {
-            return thumbnail;
-        }
-
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING && loadIfNotCached) {
-            // Load the thumbnail from the system
-            thumbnail = ssp.getTaskThumbnail(taskKey.id);
-            if (thumbnail != null) {
-                mThumbnailCache.put(taskKey, thumbnail);
-                return thumbnail;
-            }
-        }
-        // We couldn't load any thumbnail
-        return null;
-    }
-
-    /** Returns the activity's primary color. */
-    public int getActivityPrimaryColor(ActivityManager.TaskDescription td, Resources res) {
-        if (td != null && td.getPrimaryColor() != 0) {
-            return td.getPrimaryColor();
-        }
-        return res.getColor(R.color.recents_task_bar_default_background_color);
-    }
-
     /** Returns the size of the app icon cache. */
     public int getApplicationIconCacheSize() {
         return mMaxIconCacheSize;
@@ -453,8 +320,7 @@
 
     /** Creates a new plan for loading the recent tasks. */
     public RecentsTaskLoadPlan createLoadPlan(Context context) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
-        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context, config, mSystemServicesProxy);
+        RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(context);
         return plan;
     }
 
@@ -505,23 +371,18 @@
         mLoadQueue.removeTask(t);
         mThumbnailCache.remove(t.key);
         mApplicationIconCache.remove(t.key);
+        mActivityInfoCache.remove(t.key.getComponent());
         if (notifyTaskDataUnloaded) {
             t.notifyTaskDataUnloaded(null, mDefaultApplicationIcon);
         }
     }
 
-    /** Stops the task loader and clears all pending tasks */
-    void stopLoader() {
-        mLoader.stop();
-        mLoadQueue.clearTasks();
-    }
-
     /**
      * Handles signals from the system, trimming memory when requested to prevent us from running
      * out of memory.
      */
     public void onTrimMemory(int level) {
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        RecentsConfiguration config = Recents.getConfiguration();
         switch (level) {
             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
                 // Stop the loader immediately when the UI is no longer visible
@@ -542,18 +403,23 @@
                 // We are leaving recents, so trim the data a bit
                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 2));
                 mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 2));
+                mActivityInfoCache.trimToSize(Math.max(1,
+                        ActivityManager.getMaxRecentTasksStatic() / 2));
                 break;
             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
                 // We are going to be low on memory
                 mThumbnailCache.trimToSize(Math.max(1, mMaxThumbnailCacheSize / 4));
                 mApplicationIconCache.trimToSize(Math.max(1, mMaxIconCacheSize / 4));
+                mActivityInfoCache.trimToSize(Math.max(1,
+                        ActivityManager.getMaxRecentTasksStatic() / 4));
                 break;
             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
                 // We are low on memory, so release everything
                 mThumbnailCache.evictAll();
                 mApplicationIconCache.evictAll();
+                mActivityInfoCache.evictAll();
                 // The cache is small, only clear the label cache when we are critical
                 mActivityLabelCache.evictAll();
                 mContentDescriptionCache.evictAll();
@@ -562,4 +428,165 @@
                 break;
         }
     }
+
+    /**
+     * Returns the cached task label if the task key is not expired, updating the cache if it is.
+     */
+    String getAndUpdateActivityLabel(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
+                                     SystemServicesProxy ssp) {
+        // Return the task description label if it exists
+        if (td != null && td.getLabel() != null) {
+            return td.getLabel();
+        }
+        // Return the cached activity label if it exists
+        String label = mActivityLabelCache.getAndInvalidateIfModified(taskKey);
+        if (label != null) {
+            return label;
+        }
+        // All short paths failed, load the label from the activity info and cache it
+        ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+        if (activityInfo != null) {
+            label = ssp.getActivityLabel(activityInfo);
+            mActivityLabelCache.put(taskKey, label);
+            return label;
+        }
+        // If the activity info does not exist or fails to load, return an empty label for now,
+        // but do not cache it
+        return "";
+    }
+
+    /**
+     * Returns the cached task content description if the task key is not expired, updating the
+     * cache if it is.
+     */
+    String getAndUpdateContentDescription(Task.TaskKey taskKey, String activityLabel,
+            SystemServicesProxy ssp, Resources res) {
+        // Return the cached content description if it exists
+        String label = mContentDescriptionCache.getAndInvalidateIfModified(taskKey);
+        if (label != null) {
+            return label;
+        }
+        // If the given activity label is empty, don't compute or cache the content description
+        if (activityLabel.isEmpty()) {
+            return "";
+        }
+
+        label = ssp.getContentDescription(taskKey.baseIntent, taskKey.userId, activityLabel, res);
+        if (label != null) {
+            mContentDescriptionCache.put(taskKey, label);
+            return label;
+        }
+        // If the content description does not exist, return an empty label for now, but do not
+        // cache it
+        return "";
+    }
+
+    /**
+     * Returns the cached task icon if the task key is not expired, updating the cache if it is.
+     */
+    Drawable getAndUpdateActivityIcon(Task.TaskKey taskKey, ActivityManager.TaskDescription td,
+            SystemServicesProxy ssp, Resources res, boolean loadIfNotCached) {
+        // Return the cached activity icon if it exists
+        Drawable icon = mApplicationIconCache.getAndInvalidateIfModified(taskKey);
+        if (icon != null) {
+            return icon;
+        }
+
+        if (loadIfNotCached) {
+            // Return and cache the task description icon if it exists
+            icon = mLoader.getTaskDescriptionIcon(taskKey, td.getInMemoryIcon(),
+                    td.getIconFilename(), ssp, res);
+            if (icon != null) {
+                mApplicationIconCache.put(taskKey, icon);
+                return icon;
+            }
+
+            // Load the icon from the activity info and cache it
+            ActivityInfo activityInfo = getAndUpdateActivityInfo(taskKey, ssp);
+            if (activityInfo != null) {
+                icon = ssp.getActivityIcon(activityInfo, taskKey.userId);
+                if (icon != null) {
+                    mApplicationIconCache.put(taskKey, icon);
+                    return icon;
+                }
+            }
+        }
+        // We couldn't load any icon
+        return null;
+    }
+
+    /**
+     * Returns the cached thumbnail if the task key is not expired, updating the cache if it is.
+     */
+    Bitmap getAndUpdateThumbnail(Task.TaskKey taskKey, SystemServicesProxy ssp,
+            boolean loadIfNotCached) {
+        // Return the cached thumbnail if it exists
+        Bitmap thumbnail = mThumbnailCache.getAndInvalidateIfModified(taskKey);
+        if (thumbnail != null) {
+            return thumbnail;
+        }
+
+        if (loadIfNotCached) {
+            RecentsConfiguration config = Recents.getConfiguration();
+            if (config.svelteLevel < RecentsConfiguration.SVELTE_DISABLE_LOADING) {
+                // Load the thumbnail from the system
+                thumbnail = ssp.getTaskThumbnail(taskKey.id);
+                if (thumbnail != null) {
+                    mThumbnailCache.put(taskKey, thumbnail);
+                    return thumbnail;
+                }
+            }
+        }
+        // We couldn't load any thumbnail
+        return null;
+    }
+
+    /**
+     * Returns the task's primary color.
+     */
+    int getActivityPrimaryColor(ActivityManager.TaskDescription td) {
+        if (td != null && td.getPrimaryColor() != 0) {
+            return td.getPrimaryColor();
+        }
+        return mDefaultTaskBarBackgroundColor;
+    }
+
+    /**
+     * Returns the activity info for the given task key, retrieving one from the system if the
+     * task key is expired.
+     */
+    private ActivityInfo getAndUpdateActivityInfo(Task.TaskKey taskKey, SystemServicesProxy ssp) {
+        ComponentName cn = taskKey.getComponent();
+        ActivityInfo activityInfo = mActivityInfoCache.get(cn);
+        if (activityInfo == null) {
+            activityInfo = ssp.getActivityInfo(cn, taskKey.userId);
+            mActivityInfoCache.put(cn, activityInfo);
+        }
+        return activityInfo;
+    }
+
+    /**
+     * Stops the task loader and clears all queued, pending task loads.
+     */
+    private void stopLoader() {
+        mLoader.stop();
+        mLoadQueue.clearTasks();
+    }
+
+    /**** Event Bus Events ****/
+
+    public final void onBusEvent(PackagesChangedEvent event) {
+        // Remove all the cached activity infos for this package.  The other caches do not need to
+        // be pruned at this time, as the TaskKey expiration checks will flush them next time their
+        // cached contents are requested
+        Map<ComponentName, ActivityInfo> activityInfoCache = mActivityInfoCache.snapshot();
+        for (ComponentName cn : activityInfoCache.keySet()) {
+            if (cn.getPackageName().equals(event.packageName)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Removing activity info from cache: " + cn);
+                }
+                mActivityInfoCache.remove(cn);
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index c14adf4..60051b8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -38,38 +38,11 @@
         public void onTaskDataUnloaded();
 
         /* Notifies when a task's stack id has changed. */
-        public void onMultiStackDebugTaskStackIdChanged();
-    }
-
-    /** The ComponentNameKey represents the unique primary key for a component
-     * belonging to a specified user. */
-    public static class ComponentNameKey {
-        final ComponentName component;
-        final int userId;
-
-        public ComponentNameKey(ComponentName cn, int user) {
-            component = cn;
-            userId = user;
-        }
-
-        @Override
-        public int hashCode() {
-            return Objects.hash(component, userId);
-        }
-
-        @Override
-        public boolean equals(Object o) {
-            if (!(o instanceof ComponentNameKey)) {
-                return false;
-            }
-            return component.equals(((ComponentNameKey) o).component) &&
-                    userId == ((ComponentNameKey) o).userId;
-        }
+        public void onTaskStackIdChanged();
     }
 
     /* The Task Key represents the unique primary key for the task */
     public static class TaskKey {
-        final ComponentNameKey mComponentNameKey;
         public final int id;
         public int stackId;
         public final Intent baseIntent;
@@ -79,7 +52,6 @@
 
         public TaskKey(int id, int stackId, Intent intent, int userId, long firstActiveTime,
                 long lastActiveTime) {
-            mComponentNameKey = new ComponentNameKey(intent.getComponent(), userId);
             this.id = id;
             this.stackId = stackId;
             this.baseIntent = intent;
@@ -88,9 +60,8 @@
             this.lastActiveTime = lastActiveTime;
         }
 
-        /** Returns the component name key for this task. */
-        public ComponentNameKey getComponentNameKey() {
-            return mComponentNameKey;
+        public ComponentName getComponent() {
+            return this.baseIntent.getComponent();
         }
 
         @Override
@@ -113,7 +84,7 @@
                     + "s: " + stackId + ", "
                     + "u: " + userId + ", "
                     + "lat: " + lastActiveTime + ", "
-                    + baseIntent.getComponent().getPackageName();
+                    + getComponent().getPackageName();
         }
     }
 
@@ -134,7 +105,8 @@
     public boolean lockToTaskEnabled;
     public Bitmap icon;
     public String iconFilename;
-    TaskCallbacks mCb;
+
+    private TaskCallbacks mCb;
 
     public Task() {
         // Do nothing
@@ -194,10 +166,16 @@
     public void setStackId(int stackId) {
         key.stackId = stackId;
         if (mCb != null) {
-            mCb.onMultiStackDebugTaskStackIdChanged();
+            mCb.onTaskStackIdChanged();
         }
     }
 
+    public boolean isFreeformTask() {
+        // Temporarily disable:
+        return false;
+        // return SystemServicesProxy.isFreeformStack(key.stackId);
+    }
+
     /** Notifies the callback listeners that this task has been loaded */
     public void notifyTaskDataLoaded(Bitmap thumbnail, Drawable applicationIcon) {
         this.applicationIcon = applicationIcon;
@@ -229,7 +207,7 @@
         if (group != null) {
             groupAffiliation = Integer.toString(group.affiliation);
         }
-        return "Task (" + groupAffiliation + "): " + key.baseIntent.getComponent().getPackageName() +
+        return "Task (" + groupAffiliation + "): " + key.getComponent().getPackageName() +
                 " [" + super.toString() + "]";
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
new file mode 100644
index 0000000..6d11f14
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.model;
+
+import android.util.LruCache;
+import android.util.SparseArray;
+
+/**
+ * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
+ * recently referenced key/values will be evicted as more values than the given cache size are
+ * inserted.
+ *
+ * In addition, this also allows the caller to invalidate cached values for keys that have since
+ * changed.
+ */
+public class TaskKeyLruCache<V> {
+
+    private final SparseArray<Task.TaskKey> mKeys = new SparseArray<>();
+    private final LruCache<Integer, V> mCache;
+
+    public TaskKeyLruCache(int cacheSize) {
+        mCache = new LruCache<Integer, V>(cacheSize) {
+
+            @Override
+            protected void entryRemoved(boolean evicted, Integer taskId, V oldV, V newV) {
+                mKeys.remove(taskId);
+            }
+        };
+    }
+
+    /**
+     * Gets a specific entry in the cache with the specified key, regardless of whether the cached
+     * value is valid or not.
+     */
+    final V get(Task.TaskKey key) {
+        return mCache.get(key.id);
+    }
+
+    /**
+     * Returns the value only if the key is valid (has not been updated since the last time it was
+     * in the cache)
+     */
+    final V getAndInvalidateIfModified(Task.TaskKey key) {
+        Task.TaskKey lastKey = mKeys.get(key.id);
+        if (lastKey != null) {
+            if ((lastKey.stackId != key.stackId) || (lastKey.lastActiveTime < key.lastActiveTime)) {
+                // The task has updated (been made active since the last time it was put into the
+                // LRU cache) or the stack id for the task has changed, invalidate that cache item
+                remove(key);
+                return null;
+            }
+        }
+        // Either the task does not exist in the cache, or the last active time is the same as
+        // the key specified, so return what is in the cache
+        return mCache.get(key.id);
+    }
+
+    /** Puts an entry in the cache for a specific key. */
+    final void put(Task.TaskKey key, V value) {
+        mKeys.put(key.id, key);
+        mCache.put(key.id, value);
+    }
+
+    /** Removes a cache entry for a specific key. */
+    final void remove(Task.TaskKey key) {
+        mKeys.remove(key.id);
+        mCache.remove(key.id);
+    }
+
+    /** Removes all the entries in the cache. */
+    final void evictAll() {
+        mCache.evictAll();
+        mKeys.clear();
+    }
+
+    /** Trims the cache to a specific size */
+    final void trimToSize(int cacheSize) {
+        mCache.resize(cacheSize);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 94c2653..a96fe98 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -17,6 +17,7 @@
 package com.android.systemui.recents.model;
 
 import android.animation.ObjectAnimator;
+import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -24,13 +25,16 @@
 import android.graphics.drawable.ColorDrawable;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.misc.NamedCounter;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Random;
 
@@ -395,6 +399,21 @@
         return mTaskList.size();
     }
 
+    /**
+     * Returns the task in this stack which is the launch target.
+     */
+    public Task getLaunchTarget() {
+        ArrayList<Task> tasks = mTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.isLaunchTarget) {
+                return task;
+            }
+        }
+        return null;
+    }
+
     /** Returns the index of this task in this current task stack */
     public int indexOfTask(Task t) {
         return mTaskList.indexOf(t);
@@ -413,6 +432,21 @@
         return null;
     }
 
+    /**
+     * Returns whether this stack has freeform tasks.
+     */
+    public boolean hasFreeformTasks() {
+        ArrayList<Task> tasks = mTaskList.getTasks();
+        int taskCount = tasks.size();
+        for (int i = 0; i < taskCount; i++) {
+            Task task = tasks.get(i);
+            if (task.isFreeformTask()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /******** Filtering ********/
 
     /** Filters the stack into tasks similar to the one specified */
@@ -423,8 +457,8 @@
         boolean filtered = mTaskList.setFilter(new TaskFilter() {
             @Override
             public boolean acceptTask(Task at, int i) {
-                return t.key.baseIntent.getComponent().getPackageName().equals(
-                        at.key.baseIntent.getComponent().getPackageName());
+                return t.key.getComponent().getPackageName().equals(
+                        at.key.getComponent().getPackageName());
             }
         });
         if (filtered && mCb != null) {
@@ -489,7 +523,7 @@
             int groupCountDown = Constants.DebugFlags.App.TaskAffiliationsGroupCount;
             for (int i = 0; i < taskCount; i++) {
                 Task t = tasks.get(i);
-                String packageName = t.key.baseIntent.getComponent().getPackageName();
+                String packageName = t.key.getComponent().getPackageName();
                 packageName = "pkg";
                 TaskGrouping group;
                 if (packageName.equals(prevPackage) && groupCountDown > 0) {
@@ -576,6 +610,37 @@
         }
     }
 
+    /**
+     * Computes the components of tasks in this stack that have been removed as a result of a change
+     * in the specified package.
+     */
+    public HashSet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
+        // Identify all the tasks that should be removed as a result of the package being removed.
+        // Using a set to ensure that we callback once per unique component.
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        HashSet<ComponentName> existingComponents = new HashSet<>();
+        HashSet<ComponentName> removedComponents = new HashSet<>();
+        ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
+        for (Task.TaskKey t : taskKeys) {
+            // Skip if this doesn't apply to the current user
+            if (t.userId != userId) continue;
+
+            ComponentName cn = t.getComponent();
+            if (cn.getPackageName().equals(packageName)) {
+                if (existingComponents.contains(cn)) {
+                    // If we know that the component still exists in the package, then skip
+                    continue;
+                }
+                if (ssp.getActivityInfo(cn, userId) != null) {
+                    existingComponents.add(cn);
+                } else {
+                    removedComponents.add(cn);
+                }
+            }
+        }
+        return removedComponents;
+    }
+
     @Override
     public String toString() {
         String str = "Tasks:\n";
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
index fb05c01..21b6bd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java
@@ -20,13 +20,12 @@
 import android.graphics.Rect;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 
 /* An outline provider that has a clip and outline that can be animated. */
 public class AnimateableViewBounds extends ViewOutlineProvider {
 
-    RecentsConfiguration mConfig;
-
     TaskView mSourceView;
     Rect mClipRect = new Rect();
     Rect mClipBounds = new Rect();
@@ -35,7 +34,6 @@
     final float mMinAlpha = 0.25f;
 
     public AnimateableViewBounds(TaskView source, int cornerRadius) {
-        mConfig = RecentsConfiguration.getInstance();
         mSourceView = source;
         mCornerRadius = cornerRadius;
         setClipBottom(getClipBottom());
@@ -64,7 +62,9 @@
             mClipRect.bottom = bottom;
             mSourceView.invalidateOutline();
             updateClipBounds();
-            if (!mConfig.useHardwareLayers) {
+
+            RecentsConfiguration config = Recents.getConfiguration();
+            if (!config.useHardwareLayers) {
                 mSourceView.mThumbnailView.updateThumbnailVisibility(
                         bottom - mSourceView.getPaddingBottom());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
new file mode 100644
index 0000000..ce993c5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.util.Log;
+import com.android.systemui.recents.model.Task;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * The layout logic for the contents of the freeform workspace.
+ */
+public class FreeformWorkspaceLayoutAlgorithm {
+
+    private static final String TAG = "FreeformWorkspaceLayoutAlgorithm";
+    private static final boolean DEBUG = false;
+
+    // The number of cells in the freeform workspace
+    private int mFreeformCellXCount;
+    private int mFreeformCellYCount;
+    // The width and height of the cells in the freeform workspace
+    private int mFreeformCellWidth;
+    private int mFreeformCellHeight;
+
+    // Optimization, allows for quick lookup of task -> index
+    private HashMap<Task.TaskKey, Integer> mTaskIndexMap = new HashMap<>();
+
+    /**
+     * Updates the layout for each of the freeform workspace tasks.  This is called after the stack
+     * layout is updated.
+     */
+    public void update(ArrayList<Task> freeformTasks, TaskStackLayoutAlgorithm stackLayout) {
+        int numFreeformTasks = stackLayout.mNumFreeformTasks;
+        if (!freeformTasks.isEmpty()) {
+            // Calculate the cell width/height depending on the number of freeform tasks
+            mFreeformCellXCount = Math.max(2, (int) Math.ceil(Math.sqrt(numFreeformTasks)));
+            mFreeformCellYCount = Math.max(2, (int) Math.ceil((float) numFreeformTasks / mFreeformCellXCount));
+            mFreeformCellWidth = stackLayout.mFreeformRect.width() / mFreeformCellXCount;
+            // For now, make the cells square
+            mFreeformCellHeight = mFreeformCellWidth;
+
+            // Put each of the tasks in the progress map at a fixed index (does not need to actually
+            // map to a scroll position, just by index)
+            int taskCount = freeformTasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                Task task = freeformTasks.get(i);
+                mTaskIndexMap.put(task.key, i);
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "mFreeformCellXCount: " + mFreeformCellXCount);
+                Log.d(TAG, "mFreeformCellYCount: " + mFreeformCellYCount);
+                Log.d(TAG, "mFreeformCellWidth: " + mFreeformCellWidth);
+                Log.d(TAG, "mFreeformCellHeight: " + mFreeformCellHeight);
+            }
+        }
+    }
+
+    /**
+     * Returns whether the transform is available for the given task.
+     */
+    public boolean isTransformAvailable(Task task, float stackScroll,
+            TaskStackLayoutAlgorithm stackLayout) {
+        if (stackLayout.mNumFreeformTasks == 0 || task == null ||
+                !mTaskIndexMap.containsKey(task.key)) {
+            return false;
+        }
+        return stackScroll > stackLayout.mStackEndScrollP;
+    }
+
+    /**
+     * Returns the transform for the given task.  Any rect returned will be offset by the actual
+     * transform for the freeform workspace.
+     */
+    public TaskViewTransform getTransform(Task task, float stackScroll,
+            TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
+        if (Float.compare(stackScroll, stackLayout.mStackEndScrollP) > 0) {
+            // This is a freeform task, so lay it out in the freeform workspace
+            int taskIndex = mTaskIndexMap.get(task.key);
+            int x = taskIndex % mFreeformCellXCount;
+            int y = taskIndex / mFreeformCellXCount;
+            float scale = (float) mFreeformCellWidth / stackLayout.mTaskRect.width();
+            int scaleXOffset = (int) (((1f - scale) * stackLayout.mTaskRect.width()) / 2);
+            int scaleYOffset = (int) (((1f - scale) * stackLayout.mTaskRect.height()) / 2);
+            transformOut.scale = scale * 0.9f;
+            transformOut.translationX = x * mFreeformCellWidth - scaleXOffset;
+            transformOut.translationY = y * mFreeformCellHeight - scaleYOffset;
+            transformOut.visible = true;
+            return transformOut;
+        }
+        return null;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index c2400df..422e917 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -42,18 +42,18 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsAppWidgetHostView;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
@@ -69,6 +69,7 @@
 public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
 
     private static final String TAG = "RecentsView";
+    private static final boolean DEBUG = false;
 
     private static final boolean ADD_HEADER_BITMAP = true;
 
@@ -80,7 +81,6 @@
         public void runAfterPause(Runnable r);
     }
 
-    RecentsConfiguration mConfig;
     LayoutInflater mInflater;
 
     ArrayList<TaskStack> mStacks;
@@ -116,7 +116,6 @@
     public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         setWillNotDraw(false);
-        mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
                 com.android.internal.R.interpolator.fast_out_slow_in);
@@ -130,7 +129,8 @@
 
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
-        if (mConfig.getLaunchState().launchedReuseTaskStackViews) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        if (config.getLaunchState().launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
                 mTaskStackView.reset();
@@ -310,13 +310,14 @@
      */
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        RecentsConfiguration config = Recents.getConfiguration();
         int width = MeasureSpec.getSize(widthMeasureSpec);
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         // Get the search bar bounds and measure the search bar layout
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
-            mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
+            config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
                     searchBarSpaceBounds);
             mSearchBar.measure(
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
@@ -324,7 +325,7 @@
         }
 
         Rect taskStackBounds = new Rect();
-        mConfig.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
+        config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
                 mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
         if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
             mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets);
@@ -345,11 +346,13 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        RecentsConfiguration config = Recents.getConfiguration();
+
         // Get the search bar bounds so that we lay it out
         Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
-            mConfig.getSearchBarBounds(measuredRect,
+            config.getSearchBarBounds(measuredRect,
                     mSystemInsets.top, searchBarSpaceBounds);
             mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
                     searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
@@ -404,30 +407,6 @@
         return super.verifyDrawable(who);
     }
 
-    /** Notifies each task view of the user interaction. */
-    public void onUserInteraction() {
-        // Get the first stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.onUserInteraction();
-        }
-    }
-
-    /** Focuses the next task in the first stack view */
-    public void focusNextTask(boolean forward) {
-        // Get the first stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.focusNextTask(forward, true);
-        }
-    }
-
-    /** Dismisses the focused task. */
-    public void dismissFocusedTask() {
-        // Get the first stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.dismissFocusedTask();
-        }
-    }
-
     /** Unfilters any filtered stacks */
     public boolean unfilterFilteredStacks() {
         if (mStacks != null) {
@@ -497,7 +476,7 @@
                 new AppTransitionAnimationSpec[specs.size()];
         try {
             WindowManagerGlobal.getWindowManagerService().overridePendingAppTransitionMultiThumb(
-                    specs.toArray(specsArray), callback, true /* scaleUp */);
+                    specs.toArray(specsArray), callback, null, true /* scaleUp */);
 
         } catch (RemoteException e) {
             Log.w(TAG, "Error overriding app transition", e);
@@ -570,7 +549,7 @@
         // Disable any focused state before we draw the header
         // Upfront the processing of the thumbnail
         if (tv.isFocusedTask()) {
-            tv.unsetFocusedTask();
+            tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
         }
         TaskViewTransform transform = new TaskViewTransform();
         transform = stackView.getStackAlgorithm().getStackTransform(tv.mTask, stackScroll,
@@ -602,8 +581,8 @@
 
         final int left = pts[0] + offsetX;
         final int top = pts[1] + offsetY;
-        final Rect rect = new Rect(left, top, left + transform.rect.width(),
-                top + transform.rect.height());
+        final Rect rect = new Rect(left, top, left + (int) transform.rect.width(),
+                top + (int) transform.rect.height());
 
         return new AppTransitionAnimationSpec(taskId, b, rect);
     }
@@ -630,15 +609,14 @@
             // and then offset to the expected transform rect, but bound this to just
             // outside the display rect (to ensure we don't animate from too far away)
             sourceView = stackView;
-            offsetX = transform.rect.left;
+            offsetX = (int) transform.rect.left;
             offsetY = getMeasuredHeight();
         } else {
             sourceView = tv.mThumbnailView;
         }
 
         // Compute the thumbnail to scale up from
-        final SystemServicesProxy ssp =
-                RecentsTaskLoader.getInstance().getSystemServicesProxy();
+        final SystemServicesProxy ssp = Recents.getSystemServices();
         ActivityOptions opts = null;
         ActivityOptions.OnAnimationStartedListener animStartedListener = null;
         if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
@@ -652,8 +630,6 @@
                             postDelayed(new Runnable() {
                                 @Override
                                 public void run() {
-                                    RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                                    SystemServicesProxy ssp = loader.getSystemServicesProxy();
                                     EventBus.getDefault().send(new ScreenPinningRequestEvent(
                                             getContext(), ssp));
                                 }
@@ -667,7 +643,7 @@
                     animStartedListener, destinationStack);
             opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
                     Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
-                    offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+                    offsetX, offsetY, (int) transform.rect.width(), (int) transform.rect.height(),
                     sourceView.getHandler(), animStartedListener);
         } else {
             opts = ActivityOptions.makeBasic();
@@ -687,15 +663,13 @@
                     if (ssp.startActivityFromRecents(getContext(), task.key.id,
                             task.activityLabel, launchOpts)) {
                         if (screenPinningRequested) {
-                            RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                            SystemServicesProxy ssp = loader.getSystemServicesProxy();
                             EventBus.getDefault().send(new ScreenPinningRequestEvent(
                                     getContext(), ssp));
                         }
                     } else {
                         // Dismiss the task and return the user to home if we fail to
                         // launch the task
-                        EventBus.getDefault().send(new DismissTaskEvent(task, tv));
+                        EventBus.getDefault().send(new DismissTaskViewEvent(task, tv));
                         if (mCb != null) {
                             mCb.onTaskLaunchFailed();
                         }
@@ -748,14 +722,6 @@
         MetricsLogger.count(getContext(), "overview_task_all_dismissed", 1);
     }
 
-    /** Final callback after Recents is finally hidden. */
-    public void onRecentsHidden() {
-        // Notify each task stack view
-        if (mTaskStackView != null) {
-            mTaskStackView.onRecentsHidden();
-        }
-    }
-
     @Override
     public void onTaskStackFilterTriggered() {
         // Hide the search bar
@@ -820,9 +786,8 @@
 
                 // Dock the new task if we are hovering over a valid dock state
                 if (event.dockState != TaskStack.DockState.NONE) {
-                    SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-                    ssp.setTaskResizeable(event.task.key.id);
-                    ssp.dockTask(event.task.key.id, event.dockState.createMode);
+                    SystemServicesProxy ssp = Recents.getSystemServices();
+                    ssp.startTaskInDockedMode(event.task.key.id, event.dockState.createMode);
                     launchTask(event.task, null, INVALID_STACK_ID);
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 76399f4..f3a4390 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.view.MotionEvent;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.dragndrop.DragDockStateChangedEvent;
@@ -34,14 +35,16 @@
  */
 class DockRegion {
     public static TaskStack.DockState[] PHONE_LANDSCAPE = {
-            TaskStack.DockState.LEFT, TaskStack.DockState.RIGHT
+            // We only allow docking to the left for now on small devices
+            TaskStack.DockState.LEFT
     };
     public static TaskStack.DockState[] PHONE_PORTRAIT = {
-            // We only allow docking to the top for now
+            // We only allow docking to the top for now on small devices
             TaskStack.DockState.TOP
     };
     public static TaskStack.DockState[] TABLET_LANDSCAPE = {
-            TaskStack.DockState.LEFT, TaskStack.DockState.RIGHT
+            TaskStack.DockState.LEFT,
+            TaskStack.DockState.RIGHT
     };
     public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
 }
@@ -71,7 +74,7 @@
     public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
         boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
                 Configuration.ORIENTATION_LANDSCAPE;
-        RecentsConfiguration config = RecentsConfiguration.getInstance();
+        RecentsConfiguration config = Recents.getConfiguration();
         TaskStack.DockState[] dockStates = isLandscape ?
                 (config.isLargeScreen ? DockRegion.TABLET_LANDSCAPE : DockRegion.PHONE_LANDSCAPE) :
                 (config.isLargeScreen ? DockRegion.TABLET_PORTRAIT : DockRegion.PHONE_PORTRAIT);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index e04699c1..b7c1de3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -68,6 +68,7 @@
 
     private float mInitialTouchPos;
     private boolean mDragging;
+    private float mSnapBackTranslationX;
 
     private View mCurrView;
     private boolean mCanCurrViewBeDimissed;
@@ -92,6 +93,10 @@
         mDensityScale = densityScale;
     }
 
+    public void setSnapBackTranslationX(float translationX) {
+        mSnapBackTranslationX = translationX;
+    }
+
     public void setPagingTouchSlop(float pagingTouchSlop) {
         mPagingTouchSlop = pagingTouchSlop;
     }
@@ -267,7 +272,7 @@
 
     private void snapChild(final View view, float velocity) {
         final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
-        ValueAnimator anim = createTranslationAnimation(view, 0);
+        ValueAnimator anim = createTranslationAnimation(view, mSnapBackTranslationX);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
         anim.setInterpolator(mLinearOutSlowInInterpolator);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 5fbea00..c4e2d8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -22,6 +22,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
@@ -31,7 +32,6 @@
 public class SystemBarScrimViews {
 
     Context mContext;
-    RecentsConfiguration mConfig;
 
     View mStatusBarScrimView;
     View mNavBarScrimView;
@@ -48,7 +48,6 @@
 
     public SystemBarScrimViews(Activity activity) {
         mContext = activity;
-        mConfig = RecentsConfiguration.getInstance();
         mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
@@ -64,7 +63,8 @@
      * the first draw.
      */
     public void prepareEnterRecentsAnimation() {
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         mHasNavBarScrim = launchState.hasNavBarScrim();
         mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
         mHasStatusBarScrim = launchState.hasStatusBarScrim();
@@ -82,7 +82,8 @@
      * Starts animating the scrim views when entering Recents.
      */
     public final void onBusEvent(EnterRecentsWindowAnimationStartedEvent event) {
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         int transitionEnterFromAppDelay = mContext.getResources().getInteger(
                 R.integer.recents_enter_from_app_transition_duration);
         int transitionEnterFromHomeDelay = mContext.getResources().getInteger(
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
new file mode 100644
index 0000000..45d626e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -0,0 +1,630 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents.views;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.util.Log;
+import com.android.systemui.R;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.misc.ParametricCurve;
+import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+
+/**
+ * The layout logic for a TaskStackView.
+ */
+public class TaskStackLayoutAlgorithm {
+
+    private static final String TAG = "TaskStackViewLayoutAlgorithm";
+    private static final boolean DEBUG = false;
+
+    // The min scale of the last task at the top of the curve
+    private static final float STACK_PEEK_MIN_SCALE = 0.85f;
+    // The scale of the last task
+    private static final float SINGLE_TASK_SCALE = 0.95f;
+    // The percentage of the height of the stack that we want to show the last task at
+    private static final float VISIBLE_LAST_TASK_HEIGHT_PCT = 0.45f;
+    // The percentage of height of task to show between tasks
+    private static final float VISIBLE_TASK_HEIGHT_BETWEEN_TASKS = 0.5f;
+    // The percentage between the maxStackScroll and the maxScroll where a given scroll will still
+    // snap back to the maxStackScroll instead of to the maxScroll (which shows the freeform
+    // workspace)
+    private static final float SNAP_TO_MAX_STACK_SCROLL_FACTOR = 0.3f;
+
+    // A report of the visibility state of the stack
+    public class VisibilityReport {
+        public int numVisibleTasks;
+        public int numVisibleThumbnails;
+
+        /** Package level ctor */
+        VisibilityReport(int tasks, int thumbnails) {
+            numVisibleTasks = tasks;
+            numVisibleThumbnails = thumbnails;
+        }
+    }
+
+    Context mContext;
+
+    // This is the view bounds inset exactly by the search bar, but without the bottom inset
+    // see RecentsConfiguration.getTaskStackBounds()
+    public Rect mStackRect = new Rect();
+    // This is the task view bounds for layout (untransformed), the rect is top-aligned to the top
+    // of the stack rect
+    public Rect mTaskRect = new Rect();
+    // The bounds of the freeform workspace, the rect is top-aligned to the top of the stack rect
+    public Rect mFreeformRect = new Rect();
+    // This is the current system insets
+    public Rect mSystemInsets = new Rect();
+
+    // The smallest scroll progress, at this value, the back most task will be visible
+    float mMinScrollP;
+    // The largest scroll progress, at this value, the front most task will be visible above the
+    // navigation bar
+    float mMaxScrollP;
+    // The scroll progress at which bottom of the first task of the stack is aligned with the bottom
+    // of the stack
+    float mStackEndScrollP;
+    // The scroll progress that we actually want to scroll the user to when they want to go to the
+    // end of the stack (it accounts for the nav bar, so that the bottom of the task is offset from
+    // the bottom of the stack)
+    float mPreferredStackEndScrollP;
+    // The initial progress that the scroller is set when you first enter recents
+    float mInitialScrollP;
+    // The task progress for the front-most task in the stack
+    float mFrontMostTaskP;
+
+    // The relative progress to ensure that the height between affiliated tasks is respected
+    float mWithinAffiliationPOffset;
+    // The relative progress to ensure that the height between non-affiliated tasks is
+    // respected
+    float mBetweenAffiliationPOffset;
+    // The relative progress to ensure that the task height is respected
+    float mTaskHeightPOffset;
+    // The relative progress to ensure that the half task height is respected
+    float mTaskHalfHeightPOffset;
+    // The front-most task bottom offset
+    int mStackBottomOffset;
+    // The relative progress to ensure that the offset from the bottom of the stack to the bottom
+    // of the task is respected
+    float mStackBottomPOffset;
+    // The freeform workspace gap
+    int mFreeformWorkspaceGapOffset;
+    float mFreeformWorkspaceGapPOffset;
+    // The relative progress to ensure that the freeform workspace height + gap + stack bottom
+    // padding is respected
+    int mFreeformWorkspaceOffset;
+    float mFreeformWorkspacePOffset;
+
+    // The last computed task counts
+    int mNumStackTasks;
+    int mNumFreeformTasks;
+    // The min/max z translations
+    int mMinTranslationZ;
+    int mMaxTranslationZ;
+
+    // Optimization, allows for quick lookup of task -> progress
+    HashMap<Task.TaskKey, Float> mTaskProgressMap = new HashMap<>();
+
+    // The freeform workspace layout
+    FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm;
+
+    // Temporary task view transform
+    TaskViewTransform mTmpTransform = new TaskViewTransform();
+
+    // Log function
+    static ParametricCurve sCurve;
+
+    public TaskStackLayoutAlgorithm(Context context) {
+        Resources res = context.getResources();
+        mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+        mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
+        mContext = context;
+        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm();
+        if (sCurve == null) {
+            sCurve = new ParametricCurve(new ParametricCurve.CurveFunction() {
+                // The large the XScale, the longer the flat area of the curve
+                private static final float XScale = 1.75f;
+                private static final float LogBase = 3000;
+
+                float reverse(float x) {
+                    return (-x * XScale) + 1;
+                }
+
+                @Override
+                public float f(float x) {
+                    return 1f - (float) (Math.pow(LogBase, reverse(x))) / (LogBase);
+                }
+
+                @Override
+                public float invF(float y) {
+                    return (float) (Math.log(1f - reverse(y)) / (-Math.log(LogBase) * XScale));
+                }
+            }, new ParametricCurve.ParametricCurveFunction() {
+                @Override
+                public float f(float p) {
+                    // Don't scale when there are freeform tasks
+                    if (mNumFreeformTasks > 0) {
+                        return 1f;
+                    }
+
+                    if (p < 0) return STACK_PEEK_MIN_SCALE;
+                    if (p > 1) return 1f;
+                    float scaleRange = (1f - STACK_PEEK_MIN_SCALE);
+                    float scale = STACK_PEEK_MIN_SCALE + (p * scaleRange);
+                    return scale;
+                }
+            });
+        }
+    }
+
+    /**
+     * Sets the system insets.
+     */
+    public void setSystemInsets(Rect systemInsets) {
+        mSystemInsets.set(systemInsets);
+        if (DEBUG) {
+            Log.d(TAG, "setSystemInsets: " + systemInsets);
+        }
+    }
+
+    /**
+     * Computes the stack and task rects.
+     */
+    public void initialize(Rect taskStackBounds) {
+        RecentsConfiguration config = Recents.getConfiguration();
+        int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
+        int heightPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_stack_top_padding);
+
+        // Compute the stack rect, inset from the given task stack bounds
+        mStackRect.set(taskStackBounds.left + widthPadding, taskStackBounds.top + heightPadding,
+                taskStackBounds.right - widthPadding, taskStackBounds.bottom);
+        mStackBottomOffset = mSystemInsets.bottom + heightPadding;
+
+        // Compute the task rect, align it to the top-center square in the stack rect
+        int size = Math.min(mStackRect.width(), mStackRect.height() - mStackBottomOffset);
+        int xOffset = (mStackRect.width() - size) / 2;
+        mTaskRect.set(mStackRect.left + xOffset, mStackRect.top,
+                mStackRect.right - xOffset, mStackRect.top + size);
+
+        // Compute the freeform rect, align it to the top-left of the stack rect
+        mFreeformRect.set(mStackRect);
+        mFreeformRect.bottom = taskStackBounds.bottom - mStackBottomOffset;
+
+        // Compute the progress offsets
+        int withinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
+        int betweenAffiliationOffset = (int) (VISIBLE_TASK_HEIGHT_BETWEEN_TASKS * mTaskRect.height());
+        mWithinAffiliationPOffset = sCurve.computePOffsetForScaledHeight(withinAffiliationOffset,
+                mStackRect);
+        mBetweenAffiliationPOffset = sCurve.computePOffsetForScaledHeight(betweenAffiliationOffset,
+                mStackRect);
+        mTaskHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height(),
+                mStackRect);
+        mTaskHalfHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height() / 2,
+                mStackRect);
+        mStackBottomPOffset = sCurve.computePOffsetForHeight(mStackBottomOffset, mStackRect);
+        mFreeformWorkspaceGapOffset = mStackBottomOffset;
+        mFreeformWorkspaceGapPOffset = sCurve.computePOffsetForHeight(mFreeformWorkspaceGapOffset,
+                mStackRect);
+        mFreeformWorkspaceOffset = mFreeformWorkspaceGapOffset + mFreeformRect.height() +
+                mStackBottomOffset;
+        mFreeformWorkspacePOffset = sCurve.computePOffsetForHeight(mFreeformWorkspaceOffset,
+                mStackRect);
+
+        if (DEBUG) {
+            Log.d(TAG, "initialize");
+            Log.d(TAG, "\tarclength: " + sCurve.getArcLength());
+            Log.d(TAG, "\tmStackRect: " + mStackRect);
+            Log.d(TAG, "\tmTaskRect: " + mTaskRect);
+            Log.d(TAG, "\tmSystemInsets: " + mSystemInsets);
+
+            Log.d(TAG, "\tpWithinAffiliateOffset: " + mWithinAffiliationPOffset);
+            Log.d(TAG, "\tpBetweenAffiliateOffset: " + mBetweenAffiliationPOffset);
+            Log.d(TAG, "\tmTaskHeightPOffset: " + mTaskHeightPOffset);
+            Log.d(TAG, "\tmTaskHalfHeightPOffset: " + mTaskHalfHeightPOffset);
+            Log.d(TAG, "\tmStackBottomPOffset: " + mStackBottomPOffset);
+            Log.d(TAG, "\tmFreeformWorkspacePOffset: " + mFreeformWorkspacePOffset);
+            Log.d(TAG, "\tmFreeformWorkspaceGapPOffset: " + mFreeformWorkspaceGapPOffset);
+
+            Log.d(TAG, "\ty at p=0: " + sCurve.pToX(0f, mStackRect));
+            Log.d(TAG, "\ty at p=1: " + sCurve.pToX(1f, mStackRect));
+
+            for (int height = 0; height <= 2000; height += 50) {
+                float p = sCurve.computePOffsetForScaledHeight(height, mStackRect);
+                float p2 = sCurve.computePOffsetForHeight(height, mStackRect);
+                Log.d(TAG, "offset: " + height + ", " +
+                        p + " => " + (mStackRect.bottom - sCurve.pToX(1f - p, mStackRect)) /
+                                sCurve.pToScale(1f - p) + ", " +
+                        p2 + " => " + (mStackRect.bottom - sCurve.pToX(1f - p2, mStackRect)));
+            }
+        }
+    }
+
+    /**
+     * Computes the minimum and maximum scroll progress values and the progress values for each task
+     * in the stack.
+     */
+    void update(TaskStack stack) {
+        if (DEBUG) {
+            Log.d(TAG, "update");
+        }
+
+        // Clear the progress map
+        mTaskProgressMap.clear();
+
+        // Return early if we have no tasks
+        ArrayList<Task> tasks = stack.getTasks();
+        if (tasks.isEmpty()) {
+            mFrontMostTaskP = 0;
+            mMinScrollP = mMaxScrollP = mStackEndScrollP = mPreferredStackEndScrollP = 0;
+            mNumStackTasks = mNumFreeformTasks = 0;
+            return;
+        }
+
+        // Filter the set of freeform and stack tasks
+        ArrayList<Task> freeformTasks = new ArrayList<>();
+        ArrayList<Task> stackTasks = new ArrayList<>();
+        for (int i = 0; i < tasks.size(); i++) {
+            Task task = tasks.get(i);
+            if (task.isFreeformTask()) {
+                freeformTasks.add(task);
+            } else {
+                stackTasks.add(task);
+            }
+        }
+        mNumStackTasks = stackTasks.size();
+        mNumFreeformTasks = freeformTasks.size();
+
+        if (!stackTasks.isEmpty()) {
+            // Update the for each task from back to front.
+            float pAtBackMostTaskTop = 0;
+            float pAtFrontMostTaskTop = pAtBackMostTaskTop;
+            int taskCount = stackTasks.size();
+            for (int i = 0; i < taskCount; i++) {
+                Task task = stackTasks.get(i);
+                mTaskProgressMap.put(task.key, pAtFrontMostTaskTop);
+
+                if (i < (taskCount - 1)) {
+                    // Increment the peek height
+                    float pPeek = task.group.isFrontMostTask(task) ?
+                            mBetweenAffiliationPOffset : mWithinAffiliationPOffset;
+                    pAtFrontMostTaskTop += pPeek;
+                }
+            }
+
+            mFrontMostTaskP = pAtFrontMostTaskTop;
+            // Set the stack end scroll progress to the point at which the bottom of the front-most
+            // task is aligned to the bottom of the stack
+            mStackEndScrollP = alignToStackBottom(pAtFrontMostTaskTop, mTaskHeightPOffset);
+            if (mNumStackTasks > 1) {
+                // Set the preferred stack end scroll progress to the point where the bottom of the
+                // front-most task is offset by the navbar and padding from the bottom of the stack
+                mPreferredStackEndScrollP = mStackEndScrollP + mStackBottomPOffset;
+
+                // Basically align the back-most task such that the last two tasks would be visible
+                mMinScrollP = alignToStackBottom(pAtBackMostTaskTop, 2 *
+                        mBetweenAffiliationPOffset);
+            } else {
+                // When there is a single item, then just make all the stack progresses the same
+                mPreferredStackEndScrollP = mStackEndScrollP;
+                mMinScrollP = mStackEndScrollP;
+            }
+        } else {
+            // TODO: In the case where there is only freeform tasks, then the scrolls should be
+            // set to zero
+        }
+
+        if (!freeformTasks.isEmpty()) {
+            // The max scroll includes the freeform workspace offset. As the scroll progress exceeds
+            // mStackEndScrollP up to mMaxScrollP, the stack will translate upwards and the freeform
+            // workspace will be visible
+            mFreeformLayoutAlgorithm.update(freeformTasks, this);
+            mMaxScrollP = mStackEndScrollP + mFreeformWorkspacePOffset;
+            mInitialScrollP = isInitialStateFreeform(stack) ?
+                    mMaxScrollP : mPreferredStackEndScrollP;
+        } else {
+            mMaxScrollP = mPreferredStackEndScrollP;
+            mInitialScrollP = Math.max(mMinScrollP, mMaxScrollP - mTaskHalfHeightPOffset);
+        }
+
+        if (DEBUG) {
+            Log.d(TAG, "mNumStackTasks: " + mNumStackTasks);
+            Log.d(TAG, "mNumFreeformTasks: " + mNumFreeformTasks);
+            Log.d(TAG, "mMinScrollP: " + mMinScrollP);
+            Log.d(TAG, "mStackEndScrollP: " + mStackEndScrollP);
+            Log.d(TAG, "mMaxScrollP: " + mMaxScrollP);
+        }
+    }
+
+    /**
+     * Computes the maximum number of visible tasks and thumbnails.  Requires that
+     * update() is called first.
+     */
+    public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
+        // Ensure minimum visibility count
+        if (tasks.size() <= 1) {
+            return new VisibilityReport(1, 1);
+        }
+
+        // If there are freeform tasks, then they will be the only ones visible
+        int freeformTaskCount = 0;
+        for (Task t : tasks) {
+            if (t.isFreeformTask()) {
+                freeformTaskCount++;
+            }
+        }
+        if (freeformTaskCount > 0) {
+            return new VisibilityReport(freeformTaskCount, freeformTaskCount);
+        }
+
+        // Otherwise, walk backwards in the stack and count the number of tasks and visible
+        // thumbnails
+        int taskHeight = mTaskRect.height();
+        int taskBarHeight = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
+        int numVisibleTasks = 1;
+        int numVisibleThumbnails = 1;
+        float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
+        int prevScreenY = sCurve.pToX(progress, mStackRect);
+        for (int i = tasks.size() - 2; i >= 0; i--) {
+            Task task = tasks.get(i);
+            progress = mTaskProgressMap.get(task.key) - mInitialScrollP;
+            if (progress < 0) {
+                break;
+            }
+            boolean isFrontMostTaskInGroup = task.group.isFrontMostTask(task);
+            if (isFrontMostTaskInGroup) {
+                float scaleAtP = sCurve.pToScale(progress);
+                int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
+                int screenY = sCurve.pToX(progress, mStackRect) + scaleYOffsetAtP;
+                boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
+                if (hasVisibleThumbnail) {
+                    numVisibleThumbnails++;
+                    numVisibleTasks++;
+                    prevScreenY = screenY;
+                } else {
+                    // Once we hit the next front most task that does not have a visible thumbnail,
+                    // w  alk through remaining visible set
+                    for (int j = i; j >= 0; j--) {
+                        numVisibleTasks++;
+                        progress = mTaskProgressMap.get(tasks.get(j).key) - mInitialScrollP;
+                        if (progress < 0) {
+                            break;
+                        }
+                    }
+                    break;
+                }
+            } else if (!isFrontMostTaskInGroup) {
+                // Affiliated task, no thumbnail
+                numVisibleTasks++;
+            }
+        }
+        return new VisibilityReport(numVisibleTasks, numVisibleThumbnails);
+    }
+
+    /**
+     * Returns the transform for the given task.  This transform is relative to the mTaskRect, which
+     * is what the view is measured and laid out with.
+     */
+    public TaskViewTransform getStackTransform(Task task, float stackScroll,
+            TaskViewTransform transformOut, TaskViewTransform prevTransform) {
+        if (mFreeformLayoutAlgorithm.isTransformAvailable(task, stackScroll, this)) {
+            mFreeformLayoutAlgorithm.getTransform(task, stackScroll, transformOut, this);
+            if (transformOut.visible) {
+                getFreeformWorkspaceBounds(stackScroll, mTmpTransform);
+                transformOut.translationY += mTmpTransform.translationY;
+                transformOut.translationZ = mMaxTranslationZ;
+                transformOut.rect.set(mTaskRect);
+                transformOut.rect.offset(0, transformOut.translationY);
+                Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+                transformOut.p = 0;
+            }
+            return transformOut;
+        } else {
+            // Return early if we have an invalid index
+            if (task == null || !mTaskProgressMap.containsKey(task.key)) {
+                transformOut.reset();
+                return transformOut;
+            }
+            return getStackTransform(mTaskProgressMap.get(task.key), stackScroll, transformOut,
+                    prevTransform);
+        }
+    }
+
+    /** Update/get the transform */
+    public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
+            TaskViewTransform transformOut, TaskViewTransform prevTransform) {
+
+        if (mNumStackTasks == 1) {
+            // Center the task in the stack, changing the scale will not follow the curve, but just
+            // modulate some values directly
+            float pTaskRelative = mMinScrollP - stackScroll;
+            float scale = (mNumFreeformTasks > 0) ? 1f : SINGLE_TASK_SCALE;
+            int topOffset = (mStackRect.height() - mTaskRect.height()) / 2;
+            transformOut.scale = scale;
+            transformOut.translationX = 0;
+            transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height()));
+            transformOut.translationZ = mMaxTranslationZ;
+            transformOut.rect.set(mTaskRect);
+            transformOut.rect.offset(0, transformOut.translationY);
+            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+            transformOut.visible = true;
+            transformOut.p = pTaskRelative;
+            return transformOut;
+
+        } else {
+            // Once we scroll past the preferred stack end scroll, then we should start translating
+            // the cards in screen space and lock their final state at the end stack progress
+            int overscrollYOffset = 0;
+            if (mNumFreeformTasks > 0 && stackScroll > mStackEndScrollP) {
+                float stackOverscroll = (stackScroll - mPreferredStackEndScrollP) /
+                        (mFreeformWorkspacePOffset - mFreeformWorkspaceGapPOffset);
+               overscrollYOffset = (int) (Math.max(0, stackOverscroll) *
+                       (mFreeformWorkspaceOffset - mFreeformWorkspaceGapPOffset));
+                stackScroll = Math.min(mPreferredStackEndScrollP, stackScroll);
+            }
+
+            float pTaskRelative = taskProgress - stackScroll;
+            float pBounded = Math.max(0, Math.min(pTaskRelative, 1f));
+
+            // If the task top is outside of the bounds below the screen, then immediately reset it
+            if (pTaskRelative > 1f) {
+                transformOut.reset();
+                transformOut.rect.set(mTaskRect);
+                return transformOut;
+            }
+            // The check for the top is trickier, since we want to show the next task if it is at
+            // all visible, even if p < 0.
+            if (pTaskRelative < 0f) {
+                if (prevTransform != null && Float.compare(prevTransform.p, 0f) <= 0) {
+                    transformOut.reset();
+                    transformOut.rect.set(mTaskRect);
+                    return transformOut;
+                }
+            }
+            float scale = sCurve.pToScale(pBounded);
+            int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
+            transformOut.scale = scale;
+            transformOut.translationX = 0;
+            transformOut.translationY = sCurve.pToX(pBounded, mStackRect) - mStackRect.top -
+                    scaleYOffset - overscrollYOffset;
+            transformOut.translationZ = Math.max(mMinTranslationZ,
+                    mMinTranslationZ + (pBounded * (mMaxTranslationZ - mMinTranslationZ)));
+            transformOut.rect.set(mTaskRect);
+            transformOut.rect.offset(0, transformOut.translationY);
+            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+            transformOut.visible = true;
+            transformOut.p = pTaskRelative;
+            if (DEBUG) {
+                Log.d(TAG, "getStackTransform (normal): " + taskProgress + ", " + stackScroll);
+                Log.d(TAG, "\t" + transformOut);
+            }
+
+            return transformOut;
+        }
+    }
+
+    /**
+     * Returns whether this stack should be initialized to show the freeform workspace or not.
+     */
+    public boolean isInitialStateFreeform(TaskStack stack) {
+        Task launchTarget = stack.getLaunchTarget();
+        if (launchTarget != null) {
+            return launchTarget.isFreeformTask();
+        }
+        Task frontTask = stack.getFrontMostTask();
+        if (frontTask != null) {
+            return frontTask.isFreeformTask();
+        }
+        return false;
+    }
+
+    /**
+     * Update/get the transform
+     */
+    public TaskViewTransform getFreeformWorkspaceBounds(float stackScroll,
+            TaskViewTransform transformOut) {
+        transformOut.reset();
+        if (mNumFreeformTasks == 0) {
+            return transformOut;
+        }
+
+        if (stackScroll > mStackEndScrollP) {
+            // mStackEndScroll is the point at which the first stack task is bottom aligned with the
+            // stack, so we offset from on the stack rect height.
+            float stackOverscroll = (Math.max(0, stackScroll - mStackEndScrollP)) /
+                    mFreeformWorkspacePOffset;
+            int overscrollYOffset = (int) (stackOverscroll * mFreeformWorkspaceOffset);
+            transformOut.scale = 1f;
+            transformOut.alpha = 1f;
+            transformOut.translationY = mStackRect.height() + mFreeformWorkspaceGapOffset -
+                    overscrollYOffset;
+            transformOut.rect.set(mFreeformRect);
+            transformOut.rect.offset(0, transformOut.translationY);
+            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
+            transformOut.visible = true;
+        }
+        return transformOut;
+    }
+
+    /**
+     * Returns the preferred maximum scroll position for a stack at the given {@param scroll}.
+     */
+    public float getPreferredMaxScrollPosition(float scroll) {
+        float maxStackScrollBounds = mStackEndScrollP + SNAP_TO_MAX_STACK_SCROLL_FACTOR *
+                (mMaxScrollP - mStackEndScrollP);
+        if (scroll < maxStackScrollBounds) {
+            return mPreferredStackEndScrollP;
+        }
+        return mMaxScrollP;
+    }
+
+    /**
+     * Returns the untransformed task view bounds.
+     */
+    public Rect getUntransformedTaskViewBounds() {
+        return new Rect(mTaskRect);
+    }
+
+    /**
+     * Returns the scroll progress to scroll to such that the top of the task is at the top of the
+     * stack.
+     */
+    float getStackScrollForTask(Task t) {
+        if (!mTaskProgressMap.containsKey(t.key)) return 0f;
+        return mTaskProgressMap.get(t.key);
+    }
+
+    /**
+     * Maps a movement in screen y, relative to {@param downY}, to a movement in along the arc
+     * length of the curve.  We know the curve is mostly flat, so we just map the length of the
+     * screen along the arc-length proportionally (1/arclength).
+     */
+    public float getDeltaPForY(int downY, int y) {
+        float deltaP = (float) (y - downY) / mStackRect.height() * (1f / sCurve.getArcLength());
+        return -deltaP;
+    }
+
+    /**
+     * This is the inverse of {@link #getDeltaPForY}.  Given a movement along the arc length
+     * of the curve, map back to the screen y.
+     */
+    public int getYForDeltaP(float downScrollP, float p) {
+        int y = (int) ((p - downScrollP) * mStackRect.height() * sCurve.getArcLength());
+        return -y;
+    }
+
+    private float alignToStackTop(float p) {
+        // At scroll progress == p, then p is at the top of the stack
+        return p;
+    }
+
+    private float alignToStackBottom(float p, float pOffsetFromBottom) {
+        // At scroll progress == p, then p is at the top of the stack
+        // At scroll progress == p + 1, then p is at the bottom of the stack
+        return p - (1 - pOffsetFromBottom);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 6f12c52..b266eaa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -20,9 +20,11 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -30,16 +32,22 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import com.android.systemui.R;
+import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
+import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
+import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
@@ -58,6 +66,9 @@
         TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
         ViewPool.ViewPoolConsumer<TaskView, Task> {
 
+    private final static String TAG = "TaskStackView";
+    private final static boolean DEBUG = false;
+
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
@@ -66,33 +77,33 @@
         public void onTaskStackFilterTriggered();
         public void onTaskStackUnfilterTriggered();
     }
-    RecentsConfiguration mConfig;
 
     TaskStack mStack;
-    TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
+    TaskStackLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewFilterAlgorithm mFilterAlgorithm;
     TaskStackViewScroller mStackScroller;
     TaskStackViewTouchHandler mTouchHandler;
     TaskStackViewCallbacks mCb;
+    ColorDrawable mFreeformWorkspaceBackground;
     ViewPool<TaskView, Task> mViewPool;
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
     DozeTrigger mUIDozeTrigger;
     int mFocusedTaskIndex = -1;
-    int mPrevAccessibilityFocusedIndex = -1;
     // Optimizations
     int mStackViewsAnimationDuration;
     boolean mStackViewsDirty = true;
     boolean mStackViewsClipDirty = true;
     boolean mAwaitingFirstLayout = true;
     boolean mStartEnterAnimationRequestedAfterLayout;
-    boolean mStartEnterAnimationCompleted;
     ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext;
+
     Rect mTaskStackBounds = new Rect();
     int[] mTmpVisibleRange = new int[2];
-    float[] mTmpCoord = new float[2];
-    Matrix mTmpMatrix = new Matrix();
     Rect mTmpRect = new Rect();
+    RectF mTmpTaskRect = new RectF();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
+    TaskViewTransform mTmpStackBackTransform = new TaskViewTransform();
+    TaskViewTransform mTmpStackFrontTransform = new TaskViewTransform();
     HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>();
     ArrayList<TaskView> mTaskViews = new ArrayList<>();
     List<TaskView> mImmutableTaskViews = new ArrayList<>();
@@ -112,10 +123,9 @@
         super(context);
         // Set the stack first
         setStack(stack);
-        mConfig = RecentsConfiguration.getInstance();
         mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
-        mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig);
+        mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context);
         mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
         mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
         mStackScroller.setCallbacks(this);
@@ -136,6 +146,8 @@
             }
         });
         setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        mFreeformWorkspaceBackground = new ColorDrawable(0x33000000);
     }
 
     /** Sets the callbacks */
@@ -217,7 +229,6 @@
         mStackViewsDirty = true;
         mStackViewsClipDirty = true;
         mAwaitingFirstLayout = true;
-        mPrevAccessibilityFocusedIndex = -1;
         if (mUIDozeTrigger != null) {
             mUIDozeTrigger.stopDozing();
             mUIDozeTrigger.resetTrigger();
@@ -264,7 +275,7 @@
     }
 
     /** Returns the stack algorithm for this task stack. */
-    public TaskStackViewLayoutAlgorithm getStackAlgorithm() {
+    public TaskStackLayoutAlgorithm getStackAlgorithm() {
         return mLayoutAlgorithm;
     }
 
@@ -330,21 +341,24 @@
     /** Synchronizes the views with the model */
     boolean synchronizeStackViewsWithModel() {
         if (mStackViewsDirty) {
-            RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-            SystemServicesProxy ssp = loader.getSystemServicesProxy();
-
             // Get all the task transforms
             ArrayList<Task> tasks = mStack.getTasks();
             float stackScroll = mStackScroller.getStackScroll();
             int[] visibleRange = mTmpVisibleRange;
             boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
                     stackScroll, visibleRange, false);
+            boolean hasStackBackTransform = false;
+            boolean hasStackFrontTransform = false;
+            if (DEBUG) {
+                Log.d(TAG, "visibleRange: " + visibleRange[0] + " to " + visibleRange[1]);
+            }
 
             // Return all the invisible children to the pool
             mTmpTaskViewMap.clear();
             List<TaskView> taskViews = getTaskViews();
+            boolean wasLastFocusedTaskAnimated = false;
+            int lastFocusedTaskIndex = -1;
             int taskViewCount = taskViews.size();
-            boolean reaquireAccessibilityFocus = false;
             for (int i = taskViewCount - 1; i >= 0; i--) {
                 TaskView tv = taskViews.get(i);
                 Task task = tv.getTask();
@@ -352,8 +366,12 @@
                 if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) {
                     mTmpTaskViewMap.put(task, tv);
                 } else {
+                    if (tv.isFocusedTask()) {
+                        wasLastFocusedTaskAnimated = tv.isFocusAnimated();
+                        lastFocusedTaskIndex = taskIndex;
+                        resetFocusedTask();
+                    }
                     mViewPool.returnViewToPool(tv);
-                    reaquireAccessibilityFocus |= (i == mPrevAccessibilityFocusedIndex);
                 }
             }
 
@@ -373,35 +391,47 @@
                         // For items in the list, put them in start animating them from the
                         // approriate ends of the list where they are expected to appear
                         if (Float.compare(transform.p, 0f) <= 0) {
-                            mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpTransform, null);
+                            if (!hasStackBackTransform) {
+                                hasStackBackTransform = true;
+                                mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpStackBackTransform,
+                                        null);
+                            }
+                            tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0);
                         } else {
-                            mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpTransform, null);
+                            if (!hasStackFrontTransform) {
+                                hasStackFrontTransform = true;
+                                mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpStackFrontTransform,
+                                        null);
+                            }
+                            tv.updateViewPropertiesToTaskTransform(mTmpStackFrontTransform, 0);
                         }
-                        tv.updateViewPropertiesToTaskTransform(mTmpTransform, 0);
                     }
                 }
 
                 // Animate the task into place
                 tv.updateViewPropertiesToTaskTransform(mCurrentTaskTransforms.get(taskIndex),
                         mStackViewsAnimationDuration, mRequestUpdateClippingListener);
+            }
 
-                // Request accessibility focus on the next view if we removed the task
-                // that previously held accessibility focus
-                if (reaquireAccessibilityFocus) {
-                    taskViews = getTaskViews();
-                    taskViewCount = taskViews.size();
-                    if (taskViewCount > 0 && ssp.isTouchExplorationEnabled() &&
-                            mPrevAccessibilityFocusedIndex != -1) {
-                        TaskView atv = taskViews.get(taskViewCount - 1);
-                        int indexOfTask = mStack.indexOfTask(atv.getTask());
-                        if (mPrevAccessibilityFocusedIndex != indexOfTask) {
-                            tv.requestAccessibilityFocus();
-                            mPrevAccessibilityFocusedIndex = indexOfTask;
-                        }
-                    }
+            // Update the focus if the previous focused task was returned to the view pool
+            if (lastFocusedTaskIndex != -1) {
+                if (lastFocusedTaskIndex < visibleRange[1]) {
+                    setFocusedTask(visibleRange[1], false, wasLastFocusedTaskAnimated);
+                } else {
+                    setFocusedTask(visibleRange[0], false, wasLastFocusedTaskAnimated);
                 }
             }
 
+            // Update the freeform workspace
+            mLayoutAlgorithm.getFreeformWorkspaceBounds(stackScroll, mTmpTransform);
+            if (mTmpTransform.visible) {
+                mTmpTransform.rect.roundOut(mTmpRect);
+                mFreeformWorkspaceBackground.setAlpha(255);
+                mFreeformWorkspaceBackground.setBounds(mTmpRect);
+            } else {
+                mFreeformWorkspaceBackground.setAlpha(0);
+            }
+
             // Reset the request-synchronize params
             mStackViewsAnimationDuration = 0;
             mStackViewsDirty = false;
@@ -411,23 +441,24 @@
         return false;
     }
 
-    /** Updates the clip for each of the task views. */
+    /**
+     * Updates the clip for each of the task views from back to front.
+     */
     void clipTaskViews() {
         // Update the clip on each task child
         List<TaskView> taskViews = getTaskViews();
+        TaskView tmpTv = null;
         int taskViewCount = taskViews.size();
-        for (int i = 0; i < taskViewCount - 1; i++) {
+        for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
-            TaskView nextTv = null;
-            TaskView tmpTv = null;
+            TaskView frontTv = null;
             int clipBottom = 0;
-            if (tv.shouldClipViewInStack()) {
+            if (i < (taskViewCount - 1) && tv.shouldClipViewInStack()) {
                 // Find the next view to clip against
-                int nextIndex = i;
-                while (nextIndex < (taskViewCount - 1)) {
-                    tmpTv = taskViews.get(++nextIndex);
-                    if (tmpTv != null && tmpTv.shouldClipViewInStack()) {
-                        nextTv = tmpTv;
+                for (int j = i + 1; j < taskViewCount; j++) {
+                    tmpTv = taskViews.get(j);
+                    if (tmpTv.shouldClipViewInStack()) {
+                        frontTv = tmpTv;
                         break;
                     }
                 }
@@ -435,30 +466,30 @@
                 // Clip against the next view, this is just an approximation since we are
                 // stacked and we can make assumptions about the visibility of the this
                 // task relative to the ones in front of it.
-                if (nextTv != null) {
-                    // Map the top edge of next task view into the local space of the current
-                    // task view to find the clip amount in local space
-                    mTmpCoord[0] = mTmpCoord[1] = 0;
-                    Utilities.mapCoordInDescendentToSelf(nextTv, this, mTmpCoord, false);
-                    Utilities.mapCoordInSelfToDescendent(tv, this, mTmpCoord, mTmpMatrix);
-                    clipBottom = (int) Math.floor(tv.getMeasuredHeight() - mTmpCoord[1]
-                            - nextTv.getPaddingTop() - 1);
+                if (frontTv != null) {
+                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
+                    mTmpTaskRect.offset(0, tv.getTranslationY());
+                    Utilities.scaleRectAboutCenter(mTmpTaskRect, tv.getScaleX());
+                    float taskBottom = mTmpTaskRect.bottom;
+                    mTmpTaskRect.set(mLayoutAlgorithm.mTaskRect);
+                    mTmpTaskRect.offset(0, frontTv.getTranslationY());
+                    Utilities.scaleRectAboutCenter(mTmpTaskRect, frontTv.getScaleX());
+                    float frontTaskTop = mTmpTaskRect.top;
+                    if (frontTaskTop < taskBottom) {
+                        // Map the stack view space coordinate (the rects) to view space
+                        clipBottom = (int) ((taskBottom - frontTaskTop) / tv.getScaleX()) - 1;
+                    }
                 }
             }
             tv.getViewBounds().setClipBottom(clipBottom);
         }
-        if (taskViewCount > 0) {
-            // The front most task should never be clipped
-            TaskView tv = taskViews.get(taskViewCount - 1);
-            tv.getViewBounds().setClipBottom(0);
-        }
         mStackViewsClipDirty = false;
     }
 
     /** Updates the min and max virtual scroll bounds */
     void updateMinMaxScroll(boolean boundScrollToNewMinMax) {
         // Compute the min and max scroll values
-        mLayoutAlgorithm.computeMinMaxScroll(mStack.getTasks());
+        mLayoutAlgorithm.update(mStack);
 
         // Debug logging
         if (boundScrollToNewMinMax) {
@@ -471,118 +502,80 @@
         return mStackScroller;
     }
 
-    /** Focuses the task at the specified index in the stack */
-    void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) {
-        // Return early if the task is already focused
-        if (taskIndex == mFocusedTaskIndex) return;
+    /**
+     * Sets the focused task to the provided (bounded taskIndex).
+     */
+    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) {
+        setFocusedTask(taskIndex, scrollToTask, animated, true);
+    }
 
-        if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
-            mFocusedTaskIndex = taskIndex;
-            mPrevAccessibilityFocusedIndex = taskIndex;
+    /**
+     * Sets the focused task to the provided (bounded taskIndex).
+     */
+    private void setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated,
+                                final boolean requestViewFocus) {
+        // Find the next task to focus
+        int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
+                Math.max(0, Math.min(mStack.getTaskCount() - 1, taskIndex)) : -1;
+        final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
+                mStack.getTasks().get(newFocusedTaskIndex) : null;
 
-            // Focus the view if possible, otherwise, focus the view after we scroll into position
-            final Task t = mStack.getTasks().get(mFocusedTaskIndex);
-            Runnable postScrollRunnable = new Runnable() {
+        // Reset the last focused task state if changed
+        if (mFocusedTaskIndex != -1) {
+            Task focusedTask = mStack.getTasks().get(mFocusedTaskIndex);
+            if (focusedTask != newFocusedTask) {
+                resetFocusedTask();
+            }
+        }
+
+        mFocusedTaskIndex = newFocusedTaskIndex;
+        if (mFocusedTaskIndex != -1) {
+            Runnable focusTaskRunnable = new Runnable() {
                 @Override
                 public void run() {
-                    TaskView tv = getChildViewForTask(t);
+                    TaskView tv = getChildViewForTask(newFocusedTask);
                     if (tv != null) {
-                        tv.setFocusedTask(animateFocusedState);
-                        tv.requestAccessibilityFocus();
+                        tv.setFocusedState(true, animated, requestViewFocus);
                     }
                 }
             };
 
-            // Scroll the view into position (just center it in the curve)
-            if (scrollToNewPosition) {
-                float newScroll = mLayoutAlgorithm.getStackScrollForTask(t) - 0.5f;
+            if (scrollToTask) {
+                // TODO: Center the newly focused task view, only if not freeform
+                float newScroll = mLayoutAlgorithm.getStackScrollForTask(newFocusedTask) - 0.5f;
                 newScroll = mStackScroller.getBoundedStackScroll(newScroll);
-                mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, postScrollRunnable);
+                mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll,
+                        focusTaskRunnable);
             } else {
-                if (postScrollRunnable != null) {
-                    postScrollRunnable.run();
-                }
+                focusTaskRunnable.run();
             }
-
         }
     }
 
     /**
-     * Ensures that there is a task focused, if nothing is focused, then we will use the task
-     * at the center of the visible stack.
+     * Sets the focused task relative to the currently focused task.
+     *
+     * @param animated determines whether to actually draw the highlight along with the change in
+     *                            focus.
      */
-    public boolean ensureFocusedTask(boolean findClosestToCenter) {
-        if (mFocusedTaskIndex < 0) {
-            List<TaskView> taskViews = getTaskViews();
-            int taskViewCount = taskViews.size();
-            if (findClosestToCenter) {
-                // If there is no task focused, then find the task that is closes to the center
-                // of the screen and use that as the currently focused task
-                int x = mLayoutAlgorithm.mStackRect.centerX();
-                int y = mLayoutAlgorithm.mStackRect.centerY();
-                for (int i = taskViewCount - 1; i >= 0; i--) {
-                    TaskView tv = taskViews.get(i);
-                    tv.getHitRect(mTmpRect);
-                    if (mTmpRect.contains(x, y)) {
-                        mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-                        mPrevAccessibilityFocusedIndex = mFocusedTaskIndex;
-                        break;
-                    }
-                }
-            }
-            // If we can't find the center task, then use the front most index
-            if (mFocusedTaskIndex < 0 && taskViewCount > 0) {
-                TaskView tv = taskViews.get(taskViewCount - 1);
-                mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-                mPrevAccessibilityFocusedIndex = mFocusedTaskIndex;
-            }
-        }
-        return mFocusedTaskIndex >= 0;
-    }
-
-    /**
-     * Focuses the next task in the stack.
-     * @param animateFocusedState determines whether to actually draw the highlight along with
-     *                            the change in focus, as well as whether to scroll to fit the
-     *                            task into view.
-     */
-    public void focusNextTask(boolean forward, boolean animateFocusedState) {
+    public void setRelativeFocusedTask(boolean forward, boolean animated) {
         // Find the next index to focus
-        int numTasks = mStack.getTaskCount();
-        if (numTasks == 0) return;
-
-        int direction = (forward ? -1 : 1);
-        int newIndex = mFocusedTaskIndex + direction;
-        if (newIndex >= 0 && newIndex <= (numTasks - 1)) {
-            newIndex = Math.max(0, Math.min(numTasks - 1, newIndex));
-            focusTask(newIndex, true, animateFocusedState);
-        }
+        int newIndex = mFocusedTaskIndex + (forward ? -1 : 1);
+        setFocusedTask(newIndex, true, animated);
     }
 
-    /** Dismisses the focused task. */
-    public void dismissFocusedTask() {
-        // Return early if the focused task index is invalid
-        if (mFocusedTaskIndex < 0 || mFocusedTaskIndex >= mStack.getTaskCount()) {
-            mFocusedTaskIndex = -1;
-            return;
-        }
-
-        Task t = mStack.getTasks().get(mFocusedTaskIndex);
-        TaskView tv = getChildViewForTask(t);
-        tv.dismissTask();
-    }
-
-    /** Resets the focused task. */
+    /**
+     * Resets the focused task.
+     */
     void resetFocusedTask() {
-        if ((0 <= mFocusedTaskIndex) && (mFocusedTaskIndex < mStack.getTaskCount())) {
+        if (mFocusedTaskIndex != -1) {
             Task t = mStack.getTasks().get(mFocusedTaskIndex);
             TaskView tv = getChildViewForTask(t);
             if (tv != null) {
-                tv.unsetFocusedTask();
+                tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
             }
         }
         mFocusedTaskIndex = -1;
-        mPrevAccessibilityFocusedIndex = -1;
     }
 
     @Override
@@ -607,12 +600,12 @@
         super.onInitializeAccessibilityNodeInfo(info);
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
-        if (taskViewCount > 1 && mPrevAccessibilityFocusedIndex != -1) {
+        if (taskViewCount > 1 && mFocusedTaskIndex != -1) {
             info.setScrollable(true);
-            if (mPrevAccessibilityFocusedIndex > 0) {
+            if (mFocusedTaskIndex > 0) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
             }
-            if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) {
+            if (mFocusedTaskIndex < mStack.getTaskCount() - 1) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
         }
@@ -628,22 +621,14 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
-        if (ensureFocusedTask(false)) {
-            switch (action) {
-                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                    if (mPrevAccessibilityFocusedIndex > 0) {
-                        focusNextTask(true, false);
-                        return true;
-                    }
-                }
-                break;
-                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                    if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) {
-                        focusNextTask(false, false);
-                        return true;
-                    }
-                }
-                break;
+        switch (action) {
+            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                setRelativeFocusedTask(true, false /* animated */);
+                return true;
+            }
+            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                setRelativeFocusedTask(false, false /* animated */);
+                return true;
             }
         }
         return false;
@@ -675,10 +660,9 @@
     }
 
     /** Computes the stack and task rects */
-    public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds,
-            boolean launchedWithAltTab, boolean launchedFromHome) {
+    public void computeRects(Rect taskStackBounds) {
         // Compute the rects in the stack algorithm
-        mLayoutAlgorithm.computeRects(windowWidth, windowHeight, taskStackBounds);
+        mLayoutAlgorithm.initialize(taskStackBounds);
 
         // Update the scroll bounds
         updateMinMaxScroll(false);
@@ -697,7 +681,7 @@
      * Computes the maximum number of visible tasks and thumbnails.  Requires that
      * updateMinMaxScrollForStack() is called first.
      */
-    public TaskStackViewLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
+    public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
         return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getTasks());
     }
 
@@ -716,9 +700,7 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         // Compute our stack/task rects
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-        computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab,
-                launchState.launchedFromHome);
+        computeRects(mTaskStackBounds);
 
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately to load all the views
@@ -739,12 +721,12 @@
                 mTmpRect.setEmpty();
             }
             tv.measure(
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
-                        MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(
-                        mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
-                        MeasureSpec.EXACTLY));
+                    MeasureSpec.makeMeasureSpec(
+                            mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
+                            MeasureSpec.EXACTLY),
+                    MeasureSpec.makeMeasureSpec(
+                            mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                            MeasureSpec.EXACTLY));
         }
 
         setMeasuredDimension(width, height);
@@ -757,7 +739,7 @@
      */
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        // Layout each of the children
+        // Layout each of the TaskViews
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
         for (int i = 0; i < taskViewCount; i++) {
@@ -767,10 +749,9 @@
             } else {
                 mTmpRect.setEmpty();
             }
-            tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left,
-                    mLayoutAlgorithm.mTaskRect.top - mTmpRect.top,
-                    mLayoutAlgorithm.mTaskRect.right + mTmpRect.right,
-                    mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom);
+            Rect taskRect = mLayoutAlgorithm.mTaskRect;
+            tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
+                    taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
         }
 
         if (mAwaitingFirstLayout) {
@@ -784,17 +765,9 @@
         int offscreenY = mLayoutAlgorithm.mStackRect.bottom;
 
         // Find the launch target task
-        Task launchTargetTask = null;
+        Task launchTargetTask = mStack.getLaunchTarget();
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
-            if (task.isLaunchTarget) {
-                launchTargetTask = task;
-                break;
-            }
-        }
 
         // Prepare the first view for its enter animation
         for (int i = taskViewCount - 1; i >= 0; i--) {
@@ -802,7 +775,8 @@
             Task task = tv.getTask();
             boolean occludesLaunchTarget = (launchTargetTask != null) &&
                     launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
-            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, occludesLaunchTarget, offscreenY);
+            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, occludesLaunchTarget,
+                    offscreenY);
         }
 
         // If the enter animation started already and we haven't completed a layout yet, do the
@@ -813,17 +787,17 @@
             mStartEnterAnimationContext = null;
         }
 
-        // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
-        // enter animation).
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-        if (launchState.launchedWithAltTab) {
-            if (launchState.launchedFromAppWithThumbnail) {
-                focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
-                        launchState.launchedHasConfigurationChanged);
-            } else {
-                focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
-                        launchState.launchedHasConfigurationChanged);
-            }
+        // Set the task focused state without requesting view focus, and leave the focus animations
+        // until after the enter-animation
+        if (!Constants.DebugFlags.App.EnableFastToggleRecents && launchTargetTask != null) {
+            setFocusedTask(mStack.indexOfTask(launchTargetTask), false /* scrollToTask */,
+                    false /* animated */, false /* requestViewFocus */);
+        } else {
+            RecentsConfiguration config = Recents.getConfiguration();
+            RecentsActivityLaunchState launchState = config.getLaunchState();
+            int taskOffset = launchState.launchedFromHome ? -1 : -2;
+            setFocusedTask(mStack.getTaskCount() + taskOffset, false /* scrollToTask */,
+                    false /* animated */, false /* requestViewFocus */);
         }
 
         // Start dozing
@@ -841,17 +815,9 @@
 
         if (mStack.getTaskCount() > 0) {
             // Find the launch target task
-            Task launchTargetTask = null;
+            Task launchTargetTask = mStack.getLaunchTarget();
             List<TaskView> taskViews = getTaskViews();
             int taskViewCount = taskViews.size();
-            for (int i = taskViewCount - 1; i >= 0; i--) {
-                TaskView tv = taskViews.get(i);
-                Task task = tv.getTask();
-                if (task.isLaunchTarget) {
-                    launchTargetTask = task;
-                    break;
-                }
-            }
 
             // Animate all the task views into view
             for (int i = taskViewCount - 1; i >= 0; i--) {
@@ -864,7 +830,8 @@
                 ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
                         launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
                 ctx.updateListener = mRequestUpdateClippingListener;
-                mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), ctx.currentTaskTransform, null);
+                mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
+                        ctx.currentTaskTransform, null);
                 tv.startEnterRecentsAnimation(ctx);
             }
 
@@ -872,33 +839,18 @@
             ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                 @Override
                 public void run() {
-                    mStartEnterAnimationCompleted = true;
                     // Poke the dozer to restart the trigger after the animation completes
                     mUIDozeTrigger.poke();
 
-                    RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-                    SystemServicesProxy ssp = loader.getSystemServicesProxy();
-                    List<TaskView> taskViews = getTaskViews();
-                    int taskViewCount = taskViews.size();
-                    if (taskViewCount > 0) {
-                        // Focus the first view if accessibility is enabled
-                        if (ssp.isTouchExplorationEnabled()) {
-                            TaskView tv = taskViews.get(taskViewCount - 1);
-                            tv.requestAccessibilityFocus();
-                            mPrevAccessibilityFocusedIndex = mStack.indexOfTask(tv.getTask());
-                        }
-                    }
-
-                    // Start the focus animation when alt-tabbing
-                    ArrayList<Task> tasks = mStack.getTasks();
-                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-                    if (launchState.launchedWithAltTab &&
-                            !launchState.launchedHasConfigurationChanged &&
-                            0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) {
-                        TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex));
-                        if (tv != null) {
-                            tv.setFocusedTask(true);
-                        }
+                    // Update the focused state here -- since we only set the focused task without
+                    // requesting view focus in onFirstLayout(), actually request view focus and
+                    // animate the focused state if we are alt-tabbing now, after the window enter
+                    // animation is completed
+                    if (mFocusedTaskIndex != -1) {
+                        RecentsConfiguration config = Recents.getConfiguration();
+                        RecentsActivityLaunchState launchState = config.getLaunchState();
+                        setFocusedTask(mFocusedTaskIndex, false /* scrollToTask */,
+                                launchState.launchedWithAltTab);
                     }
                 }
             });
@@ -953,24 +905,19 @@
         }
     }
 
-    /** Final callback after Recents is finally hidden. */
-    void onRecentsHidden() {
-        reset();
-    }
-
     public boolean isTransformedTouchPointInView(float x, float y, View child) {
         return isTransformedTouchPointInView(x, y, child, null);
     }
 
-    /** Pokes the dozer on user interaction. */
-    void onUserInteraction() {
-        // Poke the doze trigger if it is dozing
-        mUIDozeTrigger.poke();
-    }
-
     @Override
     protected void dispatchDraw(Canvas canvas) {
         mLayersDisabled = false;
+
+        // Draw the freeform workspace background
+        if (mFreeformWorkspaceBackground.getAlpha() > 0) {
+            mFreeformWorkspaceBackground.draw(canvas);
+        }
+
         super.dispatchDraw(canvas);
     }
 
@@ -992,42 +939,44 @@
     @Override
     public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
             Task newFrontMostTask) {
-        // Remove the view associated with this task, we can't rely on updateTransforms
-        // to work here because the task is no longer in the list
-        TaskView tv = getChildViewForTask(removedTask);
-        if (tv != null) {
-            mViewPool.returnViewToPool(tv);
+        if (!removedTask.isFreeformTask()) {
+            // Remove the view associated with this task, we can't rely on updateTransforms
+            // to work here because the task is no longer in the list
+            TaskView tv = getChildViewForTask(removedTask);
+            if (tv != null) {
+                mViewPool.returnViewToPool(tv);
+            }
+
+            // Get the stack scroll of the task to anchor to (since we are removing something, the front
+            // most task will be our anchor task)
+            Task anchorTask = null;
+            float prevAnchorTaskScroll = 0;
+            boolean pullStackForward = stack.getTaskCount() > 0;
+            if (pullStackForward) {
+                anchorTask = mStack.getFrontMostTask();
+                prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
+            }
+
+            // Update the min/max scroll and animate other task views into their new positions
+            updateMinMaxScroll(true);
+
+            if (wasFrontMostTask) {
+                // Since the max scroll progress is offset from the bottom of the stack, just scroll
+                // to ensure that the new front most task is now fully visible
+                mStackScroller.setStackScroll(mLayoutAlgorithm.mMaxScrollP);
+            } else if (pullStackForward) {
+                // Otherwise, offset the scroll by half the movement of the anchor task to allow the
+                // tasks behind the removed task to move forward, and the tasks in front to move back
+                float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
+                mStackScroller.setStackScroll(mStackScroller.getStackScroll() + (anchorTaskScroll
+                        - prevAnchorTaskScroll) / 2);
+                mStackScroller.boundScroll();
+            }
+
+            // Animate all the tasks into place
+            requestSynchronizeStackViewsWithModel(200);
         }
 
-        // Get the stack scroll of the task to anchor to (since we are removing something, the front
-        // most task will be our anchor task)
-        Task anchorTask = null;
-        float prevAnchorTaskScroll = 0;
-        boolean pullStackForward = stack.getTaskCount() > 0;
-        if (pullStackForward) {
-            anchorTask = mStack.getFrontMostTask();
-            prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
-        }
-
-        // Update the min/max scroll and animate other task views into their new positions
-        updateMinMaxScroll(true);
-
-        if (wasFrontMostTask) {
-            // Since the max scroll progress is offset from the bottom of the stack, just scroll
-            // to ensure that the new front most task is now fully visible
-            mStackScroller.setStackScroll(mLayoutAlgorithm.mMaxScrollP);
-        } else if (pullStackForward) {
-            // Otherwise, offset the scroll by half the movement of the anchor task to allow the
-            // tasks behind the removed task to move forward, and the tasks in front to move back
-            float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
-            mStackScroller.setStackScroll(mStackScroller.getStackScroll() + (anchorTaskScroll
-                    - prevAnchorTaskScroll) / 2);
-            mStackScroller.boundScroll();
-        }
-
-        // Animate all the tasks into place
-        requestSynchronizeStackViewsWithModel(200);
-
         // Update the new front most task
         if (newFrontMostTask != null) {
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
@@ -1142,13 +1091,8 @@
     public void prepareViewToEnterPool(TaskView tv) {
         Task task = tv.getTask();
 
-        // Clear the accessibility focus for that view
-        if (tv.isAccessibilityFocused()) {
-            tv.clearAccessibilityFocus();
-        }
-
         // Report that this tasks's data is no longer being used
-        RecentsTaskLoader.getInstance().unloadTaskData(task);
+        Recents.getTaskLoader().unloadTaskData(task);
 
         // Detach the view from the hierarchy
         detachViewFromParent(tv);
@@ -1172,21 +1116,15 @@
         tv.onTaskBound(task);
 
         // Load the task data
-        RecentsTaskLoader.getInstance().loadTaskData(task);
+        Recents.getTaskLoader().loadTaskData(task);
 
         // If the doze trigger has already fired, then update the state for this task view
         tv.setNoUserInteractionState();
 
-        // If we've finished the start animation, then ensure we always enable the focus animations
-        if (mStartEnterAnimationCompleted) {
-            tv.enableFocusAnimations();
-        }
-
         // Find the index where this task should be placed in the stack
         int insertIndex = -1;
         int taskIndex = mStack.indexOfTask(task);
         if (taskIndex != -1) {
-
             List<TaskView> taskViews = getTaskViews();
             int taskViewCount = taskViews.size();
             for (int i = 0; i < taskViewCount; i++) {
@@ -1241,13 +1179,6 @@
         }
     }
 
-    @Override
-    public void onTaskViewFocusChanged(TaskView tv, boolean focused) {
-        if (focused) {
-            mFocusedTaskIndex = mStack.indexOfTask(tv.getTask());
-        }
-    }
-
     /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
 
     @Override
@@ -1261,21 +1192,21 @@
 
     public final void onBusEvent(PackagesChangedEvent event) {
         // Compute which components need to be removed
-        HashSet<ComponentName> removedComponents = event.monitor.computeComponentsRemoved(
-                mStack.getTaskKeys(), event.packageName, event.userId);
+        HashSet<ComponentName> removedComponents = mStack.computeComponentsRemoved(
+                event.packageName, event.userId);
 
         // For other tasks, just remove them directly if they no longer exist
         ArrayList<Task> tasks = mStack.getTasks();
         for (int i = tasks.size() - 1; i >= 0; i--) {
             final Task t = tasks.get(i);
-            if (removedComponents.contains(t.key.baseIntent.getComponent())) {
-                TaskView tv = getChildViewForTask(t);
+            if (removedComponents.contains(t.key.getComponent())) {
+                final TaskView tv = getChildViewForTask(t);
                 if (tv != null) {
                     // For visible children, defer removing the task until after the animation
                     tv.startDeleteTaskAnimation(new Runnable() {
                         @Override
                         public void run() {
-                            mStack.removeTask(t);
+                            removeTaskViewFromStack(tv);
                         }
                     }, 0);
                 } else {
@@ -1286,33 +1217,66 @@
         }
     }
 
-    public final void onBusEvent(DismissTaskEvent event) {
-        TaskView tv = event.taskView;
+    public final void onBusEvent(DismissTaskViewEvent event) {
+        removeTaskViewFromStack(event.taskView);
+    }
+
+    public final void onBusEvent(FocusNextTaskViewEvent event) {
+        setRelativeFocusedTask(true, true);
+    }
+
+    public final void onBusEvent(FocusPreviousTaskViewEvent event) {
+        setRelativeFocusedTask(false, true);
+    }
+
+    public final void onBusEvent(DismissFocusedTaskViewEvent event) {
+        if (mFocusedTaskIndex != -1) {
+            Task t = mStack.getTasks().get(mFocusedTaskIndex);
+            TaskView tv = getChildViewForTask(t);
+            tv.dismissTask();
+        }
+    }
+
+    public final void onBusEvent(UserInteractionEvent event) {
+        // Poke the doze trigger on user interaction
+        mUIDozeTrigger.poke();
+    }
+
+    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+        if (!event.visible) {
+            reset();
+        }
+    }
+
+    /**
+     * Removes the task from the stack, and updates the focus to the next task in the stack if the
+     * removed TaskView was focused.
+     */
+    private void removeTaskViewFromStack(TaskView tv) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
         Task task = tv.getTask();
         int taskIndex = mStack.indexOfTask(task);
         boolean taskWasFocused = tv.isFocusedTask();
 
-        // Announce for accessibility
-        tv.announceForAccessibility(getContext().getString(R.string.accessibility_recents_item_dismissed,
-                tv.getTask().activityLabel));
+        // Reset the previously focused task before it is removed from the stack
+        resetFocusedTask();
 
-        // Remove the task from the view
+        // Announce for accessibility
+        tv.announceForAccessibility(getContext().getString(
+                R.string.accessibility_recents_item_dismissed, tv.getTask().activityLabel));
+
+        // Remove the task from the stack
         mStack.removeTask(task);
 
-        // If the dismissed task was focused, then we should focus the new task in the same index
-        if (taskWasFocused) {
-            ArrayList<Task> tasks = mStack.getTasks();
-            int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1);
-            if (nextTaskIndex >= 0) {
-                Task nextTask = tasks.get(nextTaskIndex);
-                TaskView nextTv = getChildViewForTask(nextTask);
-                if (nextTv != null) {
-                    // Focus the next task, and only animate the visible state if we are launched
-                    // from Alt-Tab
-                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
-                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
-                }
-            }
+        if (taskWasFocused || ssp.isTouchExplorationEnabled()) {
+            // If the dismissed task was focused or if we are in touch exploration mode, then focus
+            // the next task
+            RecentsConfiguration config = Recents.getConfiguration();
+            RecentsActivityLaunchState launchState = config.getLaunchState();
+            boolean isFreeformTask = taskIndex > 0 ?
+                    mStack.getTasks().get(taskIndex - 1).isFreeformTask() : false;
+            setFocusedTask(taskIndex - 1, !isFreeformTask /* scrollToTask */,
+                    launchState.launchedWithAltTab);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
deleted file mode 100644
index 9a5d9bd..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.recents.views;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.util.Log;
-import com.android.systemui.R;
-import com.android.systemui.recents.RecentsConfiguration;
-import com.android.systemui.recents.misc.ParametricCurve;
-import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.Task;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-
-/**
- * The layout logic for a TaskStackView.
- */
-public class TaskStackViewLayoutAlgorithm {
-
-    private static final boolean DEBUG = false;
-    private static final String TAG = "TaskStackViewLayoutAlgorithm";
-
-    // The min scale of the last task at the top of the curve
-    private static final float STACK_PEEK_MIN_SCALE = 0.75f;
-    // The scale of the last task
-    private static final float SINGLE_TASK_SCALE = 0.95f;
-    // The percentage of height of task to show between tasks
-    private static final float VISIBLE_TASK_HEIGHT_BETWEEN_TASKS = 0.5f;
-
-    // A report of the visibility state of the stack
-    public class VisibilityReport {
-        public int numVisibleTasks;
-        public int numVisibleThumbnails;
-
-        /** Package level ctor */
-        VisibilityReport(int tasks, int thumbnails) {
-            numVisibleTasks = tasks;
-            numVisibleThumbnails = thumbnails;
-        }
-    }
-
-    Context mContext;
-    RecentsConfiguration mConfig;
-
-    // This is the view bounds inset exactly by the search bar, but without the bottom inset
-    // see RecentsConfiguration.getTaskStackBounds()
-    public Rect mStackRect = new Rect();
-    // This is the task view bounds for layout (untransformed), the rect is top-aligned to the top
-    // of the stack rect
-    public Rect mTaskRect = new Rect();
-    // This is the current system insets
-    public Rect mSystemInsets = new Rect();
-
-    // The smallest scroll progress, at this value, the back most task will be visible
-    float mMinScrollP;
-    // The largest scroll progress, at this value, the front most task will be visible above the
-    // navigation bar
-    float mMaxScrollP;
-    // The initial progress that the scroller is set
-    float mInitialScrollP;
-
-    // The relative progress to ensure that the height between affiliated tasks is respected
-    float mWithinAffiliationPOffset;
-    // The relative progress to ensure that the height between non-affiliated tasks is
-    // respected
-    float mBetweenAffiliationPOffset;
-    // The relative progress to ensure that the task height is respected
-    float mTaskHeightPOffset;
-    // The relative progress to ensure that the half task height is respected
-    float mTaskHalfHeightPOffset;
-    // The relative progress to ensure that the offset from the bottom of the stack to the bottom
-    // of the task is respected
-    float mTaskBottomPOffset;
-    // The front-most task bottom offset
-    int mTaskBottomOffset;
-
-    // The last computed task count
-    int mNumTasks;
-    // The min/max z translations
-    int mMinTranslationZ;
-    int mMaxTranslationZ;
-
-    // Optimization, allows for quick lookup of task -> progress
-    HashMap<Task.TaskKey, Float> mTaskProgressMap = new HashMap<>();
-
-    // Log function
-    static ParametricCurve sCurve;
-
-    public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) {
-        Resources res = context.getResources();
-        mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
-        mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        mContext = context;
-        mConfig = config;
-        if (sCurve == null) {
-            sCurve = new ParametricCurve(new ParametricCurve.CurveFunction() {
-                // The large the XScale, the longer the flat area of the curve
-                private static final float XScale = 1.75f;
-                private static final float LogBase = 3000;
-
-                float reverse(float x) {
-                    return (-x * XScale) + 1;
-                }
-
-                @Override
-                public float f(float x) {
-                    return 1f - (float) (Math.pow(LogBase, reverse(x))) / (LogBase);
-                }
-
-                @Override
-                public float invF(float y) {
-                    return (float) (Math.log(1f - reverse(y)) / (-Math.log(LogBase) * XScale));
-                }
-            }, new ParametricCurve.ParametricCurveFunction() {
-                @Override
-                public float f(float p) {
-                    if (p < 0) return STACK_PEEK_MIN_SCALE;
-                    if (p > 1) return 1f;
-                    float scaleRange = (1f - STACK_PEEK_MIN_SCALE);
-                    float scale = STACK_PEEK_MIN_SCALE + (p * scaleRange);
-                    return scale;
-                }
-            });
-        }
-    }
-
-    /**
-     * Sets the system insets.
-     */
-    public void setSystemInsets(Rect systemInsets) {
-        mSystemInsets.set(systemInsets);
-        if (DEBUG) {
-            Log.d(TAG, "setSystemInsets: " + systemInsets);
-        }
-    }
-
-    /**
-     * Computes the stack and task rects
-     */
-    public void computeRects(int windowWidth, int windowHeight, Rect taskStackBounds) {
-        int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * taskStackBounds.width());
-        int heightPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_stack_top_padding);
-
-        // Compute the stack rect, inset from the given task stack bounds
-        mStackRect.set(taskStackBounds.left + widthPadding, taskStackBounds.top + heightPadding,
-                taskStackBounds.right - widthPadding, windowHeight);
-        mTaskBottomOffset = mSystemInsets.bottom + heightPadding;
-
-        // Compute the task rect, align it to the top-center square in the stack rect
-        int size = Math.min(mStackRect.width(), taskStackBounds.height() - mTaskBottomOffset);
-        int xOffset = (mStackRect.width() - size) / 2;
-        mTaskRect.set(mStackRect.left + xOffset, mStackRect.top,
-                mStackRect.right - xOffset, mStackRect.top + size);
-
-        // Compute the progress offsets
-        int withinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_task_bar_height);
-        int betweenAffiliationOffset = (int) (VISIBLE_TASK_HEIGHT_BETWEEN_TASKS * mTaskRect.height());
-        mWithinAffiliationPOffset = sCurve.computePOffsetForScaledHeight(withinAffiliationOffset,
-                mStackRect);
-        mBetweenAffiliationPOffset = sCurve.computePOffsetForScaledHeight(betweenAffiliationOffset,
-                mStackRect);
-        mTaskHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height(),
-                mStackRect);
-        mTaskHalfHeightPOffset = sCurve.computePOffsetForScaledHeight(mTaskRect.height() / 2,
-                mStackRect);
-        mTaskBottomPOffset = sCurve.computePOffsetForHeight(mTaskBottomOffset, mStackRect);
-
-        if (DEBUG) {
-            Log.d(TAG, "computeRects");
-            Log.d(TAG, "\tmStackRect: " + mStackRect);
-            Log.d(TAG, "\tmTaskRect: " + mTaskRect);
-            Log.d(TAG, "\tmSystemInsets: " + mSystemInsets);
-
-            Log.d(TAG, "\tpWithinAffiliateOffset: " + mWithinAffiliationPOffset);
-            Log.d(TAG, "\tpBetweenAffiliateOffset: " + mBetweenAffiliationPOffset);
-            Log.d(TAG, "\tmTaskHeightPOffset: " + mTaskHeightPOffset);
-            Log.d(TAG, "\tmTaskHalfHeightPOffset: " + mTaskHalfHeightPOffset);
-            Log.d(TAG, "\tmTaskBottomPOffset: " + mTaskBottomPOffset);
-
-            Log.d(TAG, "\ty at p=0: " + sCurve.pToX(0f, mStackRect));
-            Log.d(TAG, "\ty at p=1: " + sCurve.pToX(1f, mStackRect));
-
-            for (int height = 0; height <= 1000; height += 50) {
-                float p = sCurve.computePOffsetForScaledHeight(height, mStackRect);
-                float p2 = sCurve.computePOffsetForHeight(height, mStackRect);
-                Log.d(TAG, "offset: " + height + ", " +
-                        p + " => " + (mStackRect.bottom - sCurve.pToX(1f - p, mStackRect)) /
-                                sCurve.pToScale(1f - p) + ", " +
-                        p2 + " => " + (mStackRect.bottom - sCurve.pToX(1f - p2, mStackRect)));
-            }
-        }
-    }
-
-    /**
-     * Computes the minimum and maximum scroll progress values.  This method may be called before
-     * the RecentsConfiguration is set, so we need to pass in the alt-tab state.
-     */
-    void computeMinMaxScroll(ArrayList<Task> tasks) {
-        if (DEBUG) {
-            Log.d(TAG, "computeMinMaxScroll");
-        }
-
-        // Clear the progress map
-        mTaskProgressMap.clear();
-        mNumTasks = tasks.size();
-
-        // Return early if we have no tasks
-        if (tasks.isEmpty()) {
-            mMinScrollP = mMaxScrollP = 0;
-            return;
-        }
-
-        // We calculate the progress by taking the progress of the element from the bottom of the
-        // screen
-        if (mNumTasks == 1) {
-            // Just center the task in the visible stack rect
-            mMinScrollP = mMaxScrollP = mInitialScrollP = 0f;
-            mTaskProgressMap.put(tasks.get(0).key, 0f);
-        } else {
-            // Update the tasks from back to front with the new progresses. We set the initial
-            // progress to the progress at which the top of the last task is near the center of the
-            // visible stack rect.
-            float pAtBackMostTaskTop = 0;
-            float pAtFrontMostTaskTop = pAtBackMostTaskTop;
-            int taskCount = tasks.size();
-            for (int i = 0; i < taskCount; i++) {
-                Task task = tasks.get(i);
-                mTaskProgressMap.put(task.key, pAtFrontMostTaskTop);
-
-                if (i < (taskCount - 1)) {
-                    // Increment the peek height
-                    float pPeek = task.group.isFrontMostTask(task) ?
-                            mBetweenAffiliationPOffset : mWithinAffiliationPOffset;
-                    pAtFrontMostTaskTop += pPeek;
-                }
-            }
-
-            // Set the max scroll progress to the point at which the bottom of the front-most task
-            // is aligned to the bottom of the stack (including nav bar and stack padding)
-            mMaxScrollP = pAtFrontMostTaskTop - 1f + mTaskBottomPOffset + mTaskHeightPOffset;
-            // Basically align the back-most task such that its progress is the same as the top of
-            // the front most task at the max scroll
-            mMinScrollP = pAtBackMostTaskTop - 1f + mTaskBottomPOffset + mTaskHeightPOffset;
-            // The offset the inital scroll position to the front of the stack, with half the front
-            // task height visible
-            mInitialScrollP = Math.max(mMinScrollP, mMaxScrollP - mTaskHalfHeightPOffset);
-        }
-    }
-
-    /**
-     * Computes the maximum number of visible tasks and thumbnails.  Requires that
-     * computeMinMaxScroll() is called first.
-     */
-    public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) {
-        if (tasks.size() <= 1) {
-            return new VisibilityReport(1, 1);
-        }
-
-        // Walk backwards in the task stack and count the number of tasks and visible thumbnails
-        int taskHeight = mTaskRect.height();
-        int taskBarHeight = mContext.getResources().getDimensionPixelSize(
-                R.dimen.recents_task_bar_height);
-        int numVisibleTasks = 1;
-        int numVisibleThumbnails = 1;
-        float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
-        int prevScreenY = sCurve.pToX(progress, mStackRect);
-        for (int i = tasks.size() - 2; i >= 0; i--) {
-            Task task = tasks.get(i);
-            progress = mTaskProgressMap.get(task.key) - mInitialScrollP;
-            if (progress < 0) {
-                break;
-            }
-            boolean isFrontMostTaskInGroup = task.group.isFrontMostTask(task);
-            if (isFrontMostTaskInGroup) {
-                float scaleAtP = sCurve.pToScale(progress);
-                int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
-                int screenY = sCurve.pToX(progress, mStackRect) + scaleYOffsetAtP;
-                boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
-                if (hasVisibleThumbnail) {
-                    numVisibleThumbnails++;
-                    numVisibleTasks++;
-                    prevScreenY = screenY;
-                } else {
-                    // Once we hit the next front most task that does not have a visible thumbnail,
-                    // walk through remaining visible set
-                    for (int j = i; j >= 0; j--) {
-                        numVisibleTasks++;
-                        progress = mTaskProgressMap.get(tasks.get(j).key) - mInitialScrollP;
-                        if (progress < 0) {
-                            break;
-                        }
-                    }
-                    break;
-                }
-            } else if (!isFrontMostTaskInGroup) {
-                // Affiliated task, no thumbnail
-                numVisibleTasks++;
-            }
-        }
-        return new VisibilityReport(numVisibleTasks, numVisibleThumbnails);
-    }
-
-    /**
-     * Returns the transform for the given task.  This transform is relative to the mTaskRect, which
-     * is what the view is measured and laid out with.
-     */
-    public TaskViewTransform getStackTransform(Task task, float stackScroll,
-            TaskViewTransform transformOut, TaskViewTransform prevTransform) {
-        // Return early if we have an invalid index
-        if (task == null || !mTaskProgressMap.containsKey(task.key)) {
-            transformOut.reset();
-            return transformOut;
-        }
-        return getStackTransform(mTaskProgressMap.get(task.key), stackScroll, transformOut,
-                prevTransform);
-    }
-
-    /** Update/get the transform */
-    public TaskViewTransform getStackTransform(float taskProgress, float stackScroll,
-            TaskViewTransform transformOut, TaskViewTransform prevTransform) {
-        if (DEBUG) {
-            Log.d(TAG, "getStackTransform: " + stackScroll);
-        }
-
-        if (mNumTasks == 1) {
-            // Center the task in the stack, changing the scale will not follow the curve, but just
-            // modulate some values directly
-            float pTaskRelative = -stackScroll;
-            float scale = SINGLE_TASK_SCALE;
-            int topOffset = (mStackRect.height() - mTaskBottomOffset - mTaskRect.height()) / 2;
-            transformOut.scale = scale;
-            transformOut.translationY = (int) (topOffset + (pTaskRelative * mStackRect.height()));
-            transformOut.translationZ = mMaxTranslationZ;
-            transformOut.rect.set(mTaskRect);
-            transformOut.rect.offset(0, transformOut.translationY);
-            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
-            transformOut.visible = true;
-            transformOut.p = pTaskRelative;
-            return transformOut;
-        } else {
-            float pTaskRelative = taskProgress - stackScroll;
-            float pBounded = Math.max(0, Math.min(pTaskRelative, 1f));
-            // If the task top is outside of the bounds below the screen, then immediately reset it
-            if (pTaskRelative > 1f) {
-                transformOut.reset();
-                transformOut.rect.set(mTaskRect);
-                return transformOut;
-            }
-            // The check for the top is trickier, since we want to show the next task if it is at
-            // all visible, even if p < 0.
-            if (pTaskRelative < 0f) {
-                if (prevTransform != null && Float.compare(prevTransform.p, 0f) <= 0) {
-                    transformOut.reset();
-                    transformOut.rect.set(mTaskRect);
-                    return transformOut;
-                }
-            }
-            float scale = sCurve.pToScale(pBounded);
-            int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
-            transformOut.scale = scale;
-            transformOut.translationY = sCurve.pToX(pBounded, mStackRect) - mStackRect.top -
-                    scaleYOffset;
-            transformOut.translationZ = Math.max(mMinTranslationZ,
-                    mMinTranslationZ + (pBounded * (mMaxTranslationZ - mMinTranslationZ)));
-            transformOut.rect.set(mTaskRect);
-            transformOut.rect.offset(0, transformOut.translationY);
-            Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
-            transformOut.visible = true;
-            transformOut.p = pTaskRelative;
-            return transformOut;
-        }
-    }
-
-    /**
-     * Returns the untransformed task view bounds.
-     */
-    public Rect getUntransformedTaskViewBounds() {
-        return new Rect(mTaskRect);
-    }
-
-    /**
-     * Returns the scroll progress to scroll to such that the top of the task is at the top of the
-     * stack.
-     */
-    float getStackScrollForTask(Task t) {
-        if (!mTaskProgressMap.containsKey(t.key)) return 0f;
-        return mTaskProgressMap.get(t.key);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index 3d3b13d..6b92aed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.util.Log;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
@@ -29,15 +30,21 @@
 
 /* The scrolling logic for a TaskStackView */
 public class TaskStackViewScroller {
+
+    private static final String TAG = "TaskStackViewScroller";
+    private static final boolean DEBUG = false;
+
     public interface TaskStackViewScrollerCallbacks {
-        public void onScrollChanged(float p);
+        void onScrollChanged(float p);
     }
 
     Context mContext;
-    TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
+    TaskStackLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScrollerCallbacks mCb;
 
     float mStackScrollP;
+    float mFlingDownScrollP;
+    int mFlingDownY;
 
     OverScroller mScroller;
     ObjectAnimator mScrollAnimator;
@@ -45,7 +52,7 @@
 
     Interpolator mLinearOutSlowInInterpolator;
 
-    public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
+    public TaskStackViewScroller(Context context, TaskStackLayoutAlgorithm layoutAlgorithm) {
         mContext = context;
         mScroller = new OverScroller(context);
         mLayoutAlgorithm = layoutAlgorithm;
@@ -77,11 +84,6 @@
         }
     }
 
-    /** Sets the current stack scroll without calling the callback. */
-    void setStackScrollRaw(float s) {
-        mStackScrollP = s;
-    }
-
     /**
      * Sets the current stack scroll to the initial state when you first enter recents.
      * @return whether the stack progress changed.
@@ -92,6 +94,20 @@
         return Float.compare(prevStackScrollP, mStackScrollP) != 0;
     }
 
+    /**
+     * Starts a fling that is coordinated with the {@link TaskStackViewTouchHandler}.
+     */
+    public void fling(float downScrollP, int downY, int y, int velY, int minY, int maxY,
+            int overscroll) {
+        if (DEBUG) {
+            Log.d(TAG, "fling: " + downScrollP + ", downY: " + downY + ", y: " + y +
+                    ", velY: " + velY + ", minY: " + minY + ", maxY: " + maxY);
+        }
+        mFlingDownScrollP = downScrollP;
+        mFlingDownY = downY;
+        mScroller.fling(0, y, 0, velY, 0, 0, minY, maxY, 0, overscroll);
+    }
+
     /** Bounds the current scroll if necessary */
     public boolean boundScroll() {
         float curScroll = getStackScroll();
@@ -105,7 +121,8 @@
 
     /** Returns the bounded stack scroll */
     float getBoundedStackScroll(float scroll) {
-        return Math.max(mLayoutAlgorithm.mMinScrollP, Math.min(mLayoutAlgorithm.mMaxScrollP, scroll));
+        return Math.max(mLayoutAlgorithm.mMinScrollP,
+                Math.min(mLayoutAlgorithm.getPreferredMaxScrollPosition(scroll), scroll));
     }
 
     /** Returns the amount that the absolute value of how much the scroll is out of bounds. */
@@ -174,21 +191,20 @@
 
     /**** OverScroller ****/
 
+    // TODO: Remove
+    @Deprecated
     int progressToScrollRange(float p) {
         return (int) (p * mLayoutAlgorithm.mStackRect.height());
     }
 
-    float scrollRangeToProgress(int s) {
-        return (float) s / mLayoutAlgorithm.mStackRect.height();
-    }
-
     /** Called from the view draw, computes the next scroll. */
     boolean computeScroll() {
         if (mScroller.computeScrollOffset()) {
-            float scroll = scrollRangeToProgress(mScroller.getCurrY());
-            setStackScrollRaw(scroll);
-            if (mCb != null) {
-                mCb.onScrollChanged(scroll);
+            float deltaP = mLayoutAlgorithm.getDeltaPForY(mFlingDownY, mScroller.getCurrY());
+            float scroll = mFlingDownScrollP + deltaP;
+            setStackScroll(scroll);
+            if (DEBUG) {
+                Log.d(TAG, "computeScroll: " + scroll);
             }
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 1274318..9e6fb7b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -16,7 +16,10 @@
 
 package com.android.systemui.recents.views;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.Resources;
+import android.util.Log;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
@@ -28,35 +31,38 @@
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
+import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.statusbar.FlingAnimationUtils;
 
 import java.util.List;
 
 /* Handles touch events for a TaskStackView. */
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
-    static int INACTIVE_POINTER_ID = -1;
+
+    private static final String TAG = "TaskStackViewTouchHandler";
+    private static final boolean DEBUG = false;
+
+    private static int INACTIVE_POINTER_ID = -1;
 
     Context mContext;
     TaskStackView mSv;
     TaskStackViewScroller mScroller;
     VelocityTracker mVelocityTracker;
+    FlingAnimationUtils mFlingAnimUtils;
+    ValueAnimator mScrollFlingAnimator;
 
     boolean mIsScrolling;
-
-    float mInitialP;
-    float mLastP;
-    float mTotalPMotion;
-    int mInitialMotionX, mInitialMotionY;
-    int mLastMotionX, mLastMotionY;
+    float mDownScrollP;
+    int mDownX, mDownY;
     int mActivePointerId = INACTIVE_POINTER_ID;
+    int mOverscrollSize;
     TaskView mActiveTaskView = null;
 
     int mMinimumVelocity;
     int mMaximumVelocity;
     // The scroll touch slop is used to calculate when we start scrolling
     int mScrollTouchSlop;
-    // The page touch slop is used to calculate when we start swiping
-    float mPagingTouchSlop;
     // Used to calculate when a tap is outside a task view rectangle.
     final int mWindowTouchSlop;
 
@@ -65,18 +71,21 @@
 
     public TaskStackViewTouchHandler(Context context, TaskStackView sv,
             TaskStackViewScroller scroller) {
-        mContext = context;
+        Resources res = context.getResources();
         ViewConfiguration configuration = ViewConfiguration.get(context);
+        mContext = context;
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
         mScrollTouchSlop = configuration.getScaledTouchSlop();
-        mPagingTouchSlop = configuration.getScaledPagingTouchSlop();
         mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
         mSv = sv;
         mScroller = scroller;
+        mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f);
 
-        float densityScale = context.getResources().getDisplayMetrics().density;
-        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+        float densityScale = res.getDisplayMetrics().density;
+        mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll);
+        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale,
+                configuration.getScaledPagingTouchSlop());
         mSwipeHelper.setMinAlpha(1f);
     }
 
@@ -88,11 +97,6 @@
             mVelocityTracker.clear();
         }
     }
-    void initVelocityTrackerIfNotExists() {
-        if (mVelocityTracker == null) {
-            mVelocityTracker = VelocityTracker.obtain();
-        }
-    }
     void recycleVelocityTracker() {
         if (mVelocityTracker != null) {
             mVelocityTracker.recycle();
@@ -115,175 +119,71 @@
         return null;
     }
 
-    /** Constructs a simulated motion event for the current stack scroll. */
-    MotionEvent createMotionEventForStackScroll(MotionEvent ev) {
-        MotionEvent pev = MotionEvent.obtainNoHistory(ev);
-        pev.setLocation(0, mScroller.progressToScrollRange(mScroller.getStackScroll()));
-        return pev;
-    }
-
     /** Touch preprocessing for handling below */
     public boolean onInterceptTouchEvent(MotionEvent ev) {
-        // Return early if we have no children
-        boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
-        if (!hasTaskViews) {
-            return false;
-        }
-
         // Pass through to swipe helper if we are swiping
         mInterceptedBySwipeHelper = mSwipeHelper.onInterceptTouchEvent(ev);
         if (mInterceptedBySwipeHelper) {
             return true;
         }
 
-        TaskStackViewLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
-        boolean wasScrolling = mScroller.isScrolling() ||
-                (mScroller.mScrollAnimator != null && mScroller.mScrollAnimator.isRunning());
-        int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
-            case MotionEvent.ACTION_DOWN: {
-                // Save the touch down info
-                mInitialMotionX = mLastMotionX = (int) ev.getX();
-                mInitialMotionY = mLastMotionY = (int) ev.getY();
-                mInitialP = mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
-                        layoutAlgorithm.mStackRect);
-                mActivePointerId = ev.getPointerId(0);
-                mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
-                // Stop the current scroll if it is still flinging
-                mScroller.stopScroller();
-                mScroller.stopBoundScrollAnimation();
-                // Initialize the velocity tracker
-                initOrResetVelocityTracker();
-                mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-                break;
-            }
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                final int index = ev.getActionIndex();
-                mActivePointerId = ev.getPointerId(index);
-                mLastMotionX = (int) ev.getX(index);
-                mLastMotionY = (int) ev.getY(index);
-                mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
-                break;
-            }
-            case MotionEvent.ACTION_MOVE: {
-                if (mActivePointerId == INACTIVE_POINTER_ID) break;
-
-                // Initialize the velocity tracker if necessary
-                initVelocityTrackerIfNotExists();
-                mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-
-                int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                int y = (int) ev.getY(activePointerIndex);
-                int x = (int) ev.getX(activePointerIndex);
-                if (Math.abs(y - mInitialMotionY) > mScrollTouchSlop) {
-                    // Save the touch move info
-                    mIsScrolling = true;
-                    // Disallow parents from intercepting touch events
-                    final ViewParent parent = mSv.getParent();
-                    if (parent != null) {
-                        parent.requestDisallowInterceptTouchEvent(true);
-                    }
-                }
-
-                mLastMotionX = x;
-                mLastMotionY = y;
-                mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
-                break;
-            }
-            case MotionEvent.ACTION_POINTER_UP: {
-                int pointerIndex = ev.getActionIndex();
-                int pointerId = ev.getPointerId(pointerIndex);
-                if (pointerId == mActivePointerId) {
-                    // Select a new active pointer id and reset the motion state
-                    final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
-                    mActivePointerId = ev.getPointerId(newPointerIndex);
-                    mLastMotionX = (int) ev.getX(newPointerIndex);
-                    mLastMotionY = (int) ev.getY(newPointerIndex);
-                    mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
-                    mVelocityTracker.clear();
-                }
-                break;
-            }
-            case MotionEvent.ACTION_CANCEL:
-            case MotionEvent.ACTION_UP: {
-                // Animate the scroll back if we've cancelled
-                mScroller.animateBoundScroll();
-                // Reset the drag state and the velocity tracker
-                mIsScrolling = false;
-                mActivePointerId = INACTIVE_POINTER_ID;
-                mActiveTaskView = null;
-                mTotalPMotion = 0;
-                recycleVelocityTracker();
-                break;
-            }
-        }
-
-        return wasScrolling || mIsScrolling;
+        return handleTouchEvent(ev);
     }
 
     /** Handles touch events once we have intercepted them */
     public boolean onTouchEvent(MotionEvent ev) {
-        // Short circuit if we have no children
-        boolean hasTaskViews = (mSv.getTaskViews().size() > 0);
-        if (!hasTaskViews) {
-            return false;
-        }
-
         // Pass through to swipe helper if we are swiping
         if (mInterceptedBySwipeHelper && mSwipeHelper.onTouchEvent(ev)) {
             return true;
         }
 
-        // Update the velocity tracker
-        initVelocityTrackerIfNotExists();
+        handleTouchEvent(ev);
+        return true;
+    }
 
-        TaskStackViewLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
+    private boolean handleTouchEvent(MotionEvent ev) {
+        // Short circuit if we have no children
+        if (mSv.getTaskViews().size() == 0) {
+            return false;
+        }
+
+        final TaskStackLayoutAlgorithm layoutAlgorithm = mSv.mLayoutAlgorithm;
         int action = ev.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
                 // Save the touch down info
-                mInitialMotionX = mLastMotionX = (int) ev.getX();
-                mInitialMotionY = mLastMotionY = (int) ev.getY();
-                mInitialP = mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
-                        layoutAlgorithm.mStackRect);
+                mDownX = (int) ev.getX();
+                mDownY = (int) ev.getY();
+                mDownScrollP = mScroller.getStackScroll();
                 mActivePointerId = ev.getPointerId(0);
-                mActiveTaskView = findViewAtPoint(mLastMotionX, mLastMotionY);
+                mActiveTaskView = findViewAtPoint(mDownX, mDownY);
+
                 // Stop the current scroll if it is still flinging
                 mScroller.stopScroller();
                 mScroller.stopBoundScrollAnimation();
+                Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
+
                 // Initialize the velocity tracker
                 initOrResetVelocityTracker();
-                mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-                // Disallow parents from intercepting touch events
-                final ViewParent parent = mSv.getParent();
-                if (parent != null) {
-                    parent.requestDisallowInterceptTouchEvent(true);
-                }
+                mVelocityTracker.addMovement(ev);
                 break;
             }
             case MotionEvent.ACTION_POINTER_DOWN: {
                 final int index = ev.getActionIndex();
+                mDownX = (int) ev.getX();
+                mDownY = (int) ev.getY();
+                mDownScrollP = mScroller.getStackScroll();
                 mActivePointerId = ev.getPointerId(index);
-                mLastMotionX = (int) ev.getX(index);
-                mLastMotionY = (int) ev.getY(index);
-                mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY,
-                        layoutAlgorithm.mStackRect);
+                mVelocityTracker.addMovement(ev);
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mActivePointerId == INACTIVE_POINTER_ID) break;
-
-                mVelocityTracker.addMovement(createMotionEventForStackScroll(ev));
-
                 int activePointerIndex = ev.findPointerIndex(mActivePointerId);
-                int x = (int) ev.getX(activePointerIndex);
                 int y = (int) ev.getY(activePointerIndex);
-                int yTotal = Math.abs(y - mInitialMotionY);
-                float curP = layoutAlgorithm.sCurve.xToP(y, layoutAlgorithm.mStackRect);
-                float deltaP = mLastP - curP;
                 if (!mIsScrolling) {
-                    if (yTotal > mScrollTouchSlop) {
+                    if (Math.abs(y - mDownY) > mScrollTouchSlop) {
                         mIsScrolling = true;
+
                         // Disallow parents from intercepting touch events
                         final ViewParent parent = mSv.getParent();
                         if (parent != null) {
@@ -292,54 +192,17 @@
                     }
                 }
                 if (mIsScrolling) {
-                    float curStackScroll = mScroller.getStackScroll();
-                    float overScrollAmount = mScroller.getScrollAmountOutOfBounds(curStackScroll + deltaP);
-                    if (Float.compare(overScrollAmount, 0f) != 0) {
-                        // Bound the overscroll to a fixed amount, and inversely scale the y-movement
-                        // relative to how close we are to the max overscroll
-                        float maxOverScroll = mContext.getResources().getFloat(
-                                R.dimen.recents_stack_overscroll_percentage);
-                        deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
-                                / maxOverScroll));
+                    // If we just move linearly on the screen, then that would map to 1/arclength
+                    // of the curve, so just move the scroll proportional to that
+                    float deltaP = layoutAlgorithm.getDeltaPForY(mDownY, y);
+                    float curScrollP = mDownScrollP + deltaP;
+                    mScroller.setStackScroll(curScrollP);
+                    if (DEBUG) {
+                        Log.d(TAG, "scroll: " + curScrollP);
                     }
-                    mScroller.setStackScroll(curStackScroll + deltaP);
-                }
-                mLastMotionX = x;
-                mLastMotionY = y;
-                mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
-                mTotalPMotion += Math.abs(deltaP);
-                break;
-            }
-            case MotionEvent.ACTION_UP: {
-                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                int velocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
-                if (mIsScrolling && (Math.abs(velocity) > mMinimumVelocity)) {
-                    float overscrollRangePct = Math.abs((float) velocity / mMaximumVelocity);
-                    int overscrollRange = (int) (Math.min(1f, overscrollRangePct) *
-                            (Constants.Values.TaskStackView.TaskStackMaxOverscrollRange -
-                                    Constants.Values.TaskStackView.TaskStackMinOverscrollRange));
-                    mScroller.mScroller.fling(0,
-                            mScroller.progressToScrollRange(mScroller.getStackScroll()),
-                            0, velocity,
-                            0, 0,
-                            mScroller.progressToScrollRange(mSv.mLayoutAlgorithm.mMinScrollP),
-                            mScroller.progressToScrollRange(mSv.mLayoutAlgorithm.mMaxScrollP),
-                            0, Constants.Values.TaskStackView.TaskStackMinOverscrollRange +
-                                    overscrollRange);
-                    // Invalidate to kick off computeScroll
-                    mSv.invalidate();
-                } else if (mIsScrolling && mScroller.isScrollOutOfBounds()) {
-                    // Animate the scroll back into bounds
-                    mScroller.animateBoundScroll();
-                } else if (mActiveTaskView == null) {
-                    // This tap didn't start on a task.
-                    maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
                 }
 
-                mActivePointerId = INACTIVE_POINTER_ID;
-                mIsScrolling = false;
-                mTotalPMotion = 0;
-                recycleVelocityTracker();
+                mVelocityTracker.addMovement(ev);
                 break;
             }
             case MotionEvent.ACTION_POINTER_UP: {
@@ -349,34 +212,91 @@
                     // Select a new active pointer id and reset the motion state
                     final int newPointerIndex = (pointerIndex == 0) ? 1 : 0;
                     mActivePointerId = ev.getPointerId(newPointerIndex);
-                    mLastMotionX = (int) ev.getX(newPointerIndex);
-                    mLastMotionY = (int) ev.getY(newPointerIndex);
-                    mLastP = layoutAlgorithm.sCurve.xToP(mLastMotionY, layoutAlgorithm.mStackRect);
-                    mVelocityTracker.clear();
                 }
+                mVelocityTracker.addMovement(ev);
+                break;
+            }
+            case MotionEvent.ACTION_UP: {
+                mVelocityTracker.addMovement(ev);
+                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+                int activePointerIndex = ev.findPointerIndex(mActivePointerId);
+                int y = (int) ev.getY(activePointerIndex);
+                int velocity = (int) mVelocityTracker.getYVelocity(mActivePointerId);
+                float curScrollP = mScroller.getStackScroll();
+                if (mIsScrolling) {
+                    boolean hasFreeformTasks = mSv.mStack.hasFreeformTasks();
+                    if (hasFreeformTasks && velocity > 0 &&
+                            curScrollP > layoutAlgorithm.mStackEndScrollP) {
+                        // Snap to workspace
+                        float finalY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+                                layoutAlgorithm.mPreferredStackEndScrollP);
+                        mScrollFlingAnimator = ValueAnimator.ofInt(y, (int) finalY);
+                        mScrollFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                            @Override
+                            public void onAnimationUpdate(ValueAnimator animation) {
+                                float deltaP = layoutAlgorithm.getDeltaPForY(mDownY,
+                                        (Integer) animation.getAnimatedValue());
+                                float scroll = mDownScrollP + deltaP;
+                                mScroller.setStackScroll(scroll);
+                            }
+                        });
+                        mFlingAnimUtils.apply(mScrollFlingAnimator, y, finalY, velocity);
+                        mScrollFlingAnimator.start();
+                    } else if (hasFreeformTasks && velocity < 0 &&
+                            curScrollP > (layoutAlgorithm.mStackEndScrollP -
+                                    layoutAlgorithm.mTaskHalfHeightPOffset)) {
+                        // Snap to stack
+                        float finalY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+                                layoutAlgorithm.mMaxScrollP);
+                        mScrollFlingAnimator = ValueAnimator.ofInt(y, (int) finalY);
+                        mScrollFlingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+                            @Override
+                            public void onAnimationUpdate(ValueAnimator animation) {
+                                float deltaP = layoutAlgorithm.getDeltaPForY(mDownY,
+                                        (Integer) animation.getAnimatedValue());
+                                float scroll = mDownScrollP + deltaP;
+                                mScroller.setStackScroll(scroll);
+                            }
+                        });
+                        mFlingAnimUtils.apply(mScrollFlingAnimator, y, finalY, velocity);
+                        mScrollFlingAnimator.start();
+                    } else if (mScroller.isScrollOutOfBounds()) {
+                        mScroller.animateBoundScroll();
+                    } else if (Math.abs(velocity) > mMinimumVelocity) {
+                        float minY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+                                layoutAlgorithm.mPreferredStackEndScrollP);
+                        float maxY = mDownY + layoutAlgorithm.getYForDeltaP(mDownScrollP,
+                                layoutAlgorithm.mMinScrollP);
+                        mScroller.fling(mDownScrollP, mDownY, y, velocity, (int) minY, (int) maxY,
+                                mOverscrollSize);
+                        mSv.invalidate();
+                    }
+                } else if (mActiveTaskView == null) {
+                    // This tap didn't start on a task.
+                    maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
+                }
+
+                mActivePointerId = INACTIVE_POINTER_ID;
+                mIsScrolling = false;
+                recycleVelocityTracker();
                 break;
             }
             case MotionEvent.ACTION_CANCEL: {
-                if (mScroller.isScrollOutOfBounds()) {
-                    // Animate the scroll back into bounds
-                    mScroller.animateBoundScroll();
-                }
                 mActivePointerId = INACTIVE_POINTER_ID;
                 mIsScrolling = false;
-                mTotalPMotion = 0;
                 recycleVelocityTracker();
                 break;
             }
         }
-        return true;
+        return mIsScrolling;
     }
 
     /** Hides recents if the up event at (x, y) is a tap on the background area. */
     void maybeHideRecentsFromBackgroundTap(int x, int y) {
         // Ignore the up event if it's too far from its start position. The user might have been
         // trying to scroll or swipe.
-        int dx = Math.abs(mInitialMotionX - x);
-        int dy = Math.abs(mInitialMotionY - y);
+        int dx = Math.abs(mDownX - x);
+        int dy = Math.abs(mDownY - y);
         if (dx > mScrollTouchSlop || dy > mScrollTouchSlop) {
             return;
         }
@@ -408,13 +328,9 @@
                     // Find the front most task and scroll the next task to the front
                     float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL);
                     if (vScroll > 0) {
-                        if (mSv.ensureFocusedTask(true)) {
-                            mSv.focusNextTask(true, false);
-                        }
+                        mSv.setRelativeFocusedTask(true, false /* animated */);
                     } else {
-                        if (mSv.ensureFocusedTask(true)) {
-                            mSv.focusNextTask(false, false);
-                        }
+                        mSv.setRelativeFocusedTask(false, false /* animated */);
                     }
                     return true;
             }
@@ -437,6 +353,7 @@
     @Override
     public void onBeginDrag(View v) {
         TaskView tv = (TaskView) v;
+        mSwipeHelper.setSnapBackTranslationX(tv.getTranslationX());
         // Disable clipping with the stack while we are swiping
         tv.setClipViewInStack(false);
         // Disallow touch events from this task view
@@ -461,7 +378,7 @@
         // Re-enable touch events from this task view
         tv.setTouchEnabled(true);
         // Remove the task view from the stack
-        EventBus.getDefault().send(new DismissTaskEvent(tv.getTask(), tv));
+        EventBus.getDefault().send(new DismissTaskViewEvent(tv.getTask(), tv));
         // Keep track of deletions by keyboard
         MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source",
                 Constants.Metrics.DismissSourceSwipeGesture);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 802a057..57cb599 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -29,8 +29,8 @@
 import android.graphics.Point;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
-import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
@@ -40,13 +40,15 @@
 import android.widget.FrameLayout;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivity;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.ui.DismissTaskEvent;
+import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
+import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -55,15 +57,15 @@
 public class TaskView extends FrameLayout implements Task.TaskCallbacks,
         View.OnClickListener, View.OnLongClickListener {
 
+    private final static String TAG = "TaskView";
+    private final static boolean DEBUG = false;
+
     /** The TaskView callbacks */
     interface TaskViewCallbacks {
         public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask);
         public void onTaskViewClipStateChanged(TaskView tv);
-        public void onTaskViewFocusChanged(TaskView tv, boolean focused);
     }
 
-    RecentsConfiguration mConfig;
-
     float mTaskProgress;
     ObjectAnimator mTaskProgressAnimator;
     float mMaxDimScale;
@@ -76,6 +78,7 @@
     Task mTask;
     boolean mTaskDataLoaded;
     boolean mIsFocused;
+    boolean mIsFocusAnimated;
     boolean mFocusAnimationsEnabled;
     boolean mClipViewInStack;
     AnimateableViewBounds mViewBounds;
@@ -116,8 +119,8 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        RecentsConfiguration config = Recents.getConfiguration();
         Resources res = context.getResources();
-        mConfig = RecentsConfiguration.getInstance();
         mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
         mClipViewInStack = true;
         mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
@@ -130,8 +133,8 @@
                 com.android.internal.R.interpolator.decelerate_quint);
         setTaskProgress(getTaskProgress());
         setDim(getDim());
-        if (mConfig.fakeShadows) {
-            setBackground(new FakeShadowDrawable(res, mConfig));
+        if (config.fakeShadows) {
+            setBackground(new FakeShadowDrawable(res, config));
         }
         setOutlineProvider(mViewBounds);
     }
@@ -219,9 +222,11 @@
 
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
                                              ValueAnimator.AnimatorUpdateListener updateCallback) {
+        RecentsConfiguration config = Recents.getConfiguration();
+
         // Apply the transform
         toTransform.applyToTaskView(this, duration, mFastOutSlowInInterpolator, false,
-                !mConfig.fakeShadows, updateCallback);
+                !config.fakeShadows, updateCallback);
 
         // Update the task progress
         Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator);
@@ -272,7 +277,8 @@
      * first layout because the actual animation into recents may take a long time. */
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
                                              boolean occludesLaunchTarget, int offscreenY) {
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         int initialDim = getDim();
         if (launchState.launchedHasConfigurationChanged) {
             // Just load the views as-is
@@ -302,7 +308,8 @@
 
     /** Animates this task view as it enters recents */
     void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
-        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         Resources res = mContext.getResources();
         final TaskViewTransform transform = ctx.currentTaskTransform;
         final int transitionEnterFromAppDelay = res.getInteger(
@@ -317,7 +324,6 @@
                 R.integer.recents_task_enter_from_home_stagger_delay);
         final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
                 R.dimen.recents_task_view_affiliate_group_enter_offset);
-        int startDelay = 0;
 
         if (launchState.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
@@ -366,7 +372,6 @@
                     ctx.postAnimationTrigger.increment();
                 }
             }
-            startDelay = transitionEnterFromAppDelay;
 
         } else if (launchState.launchedFromHome) {
             // Animate the tasks up
@@ -376,7 +381,7 @@
 
             setScaleX(transform.scale);
             setScaleY(transform.scale);
-            if (!mConfig.fakeShadows) {
+            if (!config.fakeShadows) {
                 animate().translationZ(transform.translationZ);
             }
             animate()
@@ -395,17 +400,7 @@
                     })
                     .start();
             ctx.postAnimationTrigger.increment();
-            startDelay = delay;
         }
-
-        // Enable the focus animations from this point onwards so that they aren't affected by the
-        // window transitions
-        postDelayed(new Runnable() {
-            @Override
-            public void run() {
-                enableFocusAnimations();
-            }
-        }, startDelay);
     }
 
     public void fadeInActionButton(int delay, int duration) {
@@ -547,7 +542,7 @@
         startDeleteTaskAnimation(new Runnable() {
             @Override
             public void run() {
-                EventBus.getDefault().send(new DismissTaskEvent(mTask, tv));
+                EventBus.getDefault().send(new DismissTaskViewEvent(mTask, tv));
             }
         }, 0);
     }
@@ -557,7 +552,11 @@
      * view.
      */
     boolean shouldClipViewInStack() {
-        return mClipViewInStack && (getVisibility() == View.VISIBLE);
+        // Never clip for freeform tasks or if invisible
+        if (mTask.isFreeformTask() || getVisibility() != View.VISIBLE) {
+            return false;
+        }
+        return mClipViewInStack;
     }
 
     /** Sets whether this view should be clipped, or clipped against. */
@@ -584,8 +583,10 @@
 
     /** Returns the current dim. */
     public void setDim(int dim) {
+        RecentsConfiguration config = Recents.getConfiguration();
+
         mDimAlpha = dim;
-        if (mConfig.useHardwareLayers) {
+        if (config.useHardwareLayers) {
             // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
             if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
                 mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0));
@@ -620,6 +621,8 @@
                 anim.addListener(postAnimRunnable);
             }
             anim.start();
+        } else {
+            postAnimRunnable.onAnimationEnd(null);
         }
     }
 
@@ -641,58 +644,32 @@
     /**** View focus state ****/
 
     /**
-     * Sets the focused task explicitly. We need a separate flag because requestFocus() won't happen
-     * if the view is not currently visible, or we are in touch state (where we still want to keep
-     * track of focus).
+     * Explicitly sets the focused state of this task.
      */
-    public void setFocusedTask(boolean animateFocusedState) {
-        mIsFocused = true;
-        if (mFocusAnimationsEnabled) {
-            // Focus the header bar
-            mHeaderView.onTaskViewFocusChanged(true, animateFocusedState);
-        }
-        // Update the thumbnail alpha with the focus
-        mThumbnailView.onFocusChanged(true);
-        // Call the callback
-        if (mCb != null) {
-            mCb.onTaskViewFocusChanged(this, true);
-        }
-        // Workaround, we don't always want it focusable in touch mode, but we want the first task
-        // to be focused after the enter-recents animation, which can be triggered from either touch
-        // or keyboard
-        setFocusableInTouchMode(true);
-        requestFocus();
-        setFocusableInTouchMode(false);
-        invalidate();
-    }
-
-    /**
-     * Unsets the focused task explicitly.
-     */
-    void unsetFocusedTask() {
-        mIsFocused = false;
-        if (mFocusAnimationsEnabled) {
-            // Un-focus the header bar
-            mHeaderView.onTaskViewFocusChanged(false, true);
+    public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) {
+        if (DEBUG) {
+            Log.d(TAG, "setFocusedState: " + mTask.activityLabel + " focused: " + isFocused +
+                    " mIsFocused: " + mIsFocused + " animated: " + animated +
+                    " requestViewFocus: " + requestViewFocus + " isFocused(): " + isFocused() +
+                    " isAccessibilityFocused(): " + isAccessibilityFocused());
         }
 
-        // Update the thumbnail alpha with the focus
-        mThumbnailView.onFocusChanged(false);
-        // Call the callback
-        if (mCb != null) {
-            mCb.onTaskViewFocusChanged(this, false);
-        }
-        invalidate();
-    }
-
-    /**
-     * Updates the explicitly focused state when the view focus changes.
-     */
-    @Override
-    protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
-        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
-        if (!gainFocus) {
-            unsetFocusedTask();
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        mIsFocused = isFocused;
+        mIsFocusAnimated = animated;
+        mHeaderView.onTaskViewFocusChanged(isFocused, animated);
+        mThumbnailView.onFocusChanged(isFocused);
+        if (isFocused) {
+            if (requestViewFocus && !isFocused()) {
+                requestFocus();
+            }
+            if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
+                requestAccessibilityFocus();
+            }
+        } else {
+            if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
+                clearAccessibilityFocus();
+            }
         }
     }
 
@@ -700,17 +677,14 @@
      * Returns whether we have explicitly been focused.
      */
     public boolean isFocusedTask() {
-        return mIsFocused || isFocused();
+        return mIsFocused;
     }
 
-    /** Enables all focus animations. */
-    void enableFocusAnimations() {
-        boolean wasFocusAnimationsEnabled = mFocusAnimationsEnabled;
-        mFocusAnimationsEnabled = true;
-        if (mIsFocused && !wasFocusAnimationsEnabled) {
-            // Re-notify the header if we were focused and animations were not previously enabled
-            mHeaderView.onTaskViewFocusChanged(true, true);
-        }
+    /**
+     * Returns whether this focused task is animated.
+     */
+    public boolean isFocusAnimated() {
+        return mIsFocusAnimated;
     }
 
     public void disableLayersForOneFrame() {
@@ -734,13 +708,14 @@
 
     @Override
     public void onTaskDataLoaded() {
+        RecentsConfiguration config = Recents.getConfiguration();
         if (mThumbnailView != null && mHeaderView != null) {
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask);
             mHeaderView.rebindToTask(mTask);
             // Rebind any listeners
             mActionButtonView.setOnClickListener(this);
-            setOnLongClickListener(mConfig.hasDockedTasks ? null : this);
+            setOnLongClickListener(config.hasDockedTasks ? null : this);
         }
         mTaskDataLoaded = true;
     }
@@ -759,7 +734,7 @@
     }
 
     @Override
-    public void onMultiStackDebugTaskStackIdChanged() {
+    public void onTaskStackIdChanged() {
         mHeaderView.rebindToTask(mTask);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 949d515..649199e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -39,7 +39,6 @@
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
@@ -48,13 +47,12 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.ui.ResizeTaskEvent;
 import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
-import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 
 
@@ -62,8 +60,6 @@
 public class TaskViewHeader extends FrameLayout
         implements View.OnClickListener, View.OnLongClickListener {
 
-    RecentsConfiguration mConfig;
-    private SystemServicesProxy mSsp;
     Task mTask;
 
     // Header views
@@ -111,8 +107,6 @@
 
     public TaskViewHeader(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
-        mSsp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
         setWillNotDraw(false);
         setClipToOutline(true);
         setOutlineProvider(new ViewOutlineProvider() {
@@ -249,9 +243,8 @@
         mMoveTaskButton.setOnClickListener(this);
 
         // In accessibility, a single click on the focused app info button will show it
-        AccessibilityManager am = (AccessibilityManager) getContext().
-                getSystemService(Context.ACCESSIBILITY_SERVICE);
-        if (am != null && am.isEnabled()) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.isTouchExplorationEnabled()) {
             mApplicationIcon.setOnClickListener(this);
         }
     }
@@ -262,12 +255,17 @@
         mApplicationIcon.setImageDrawable(null);
         mApplicationIcon.setOnClickListener(null);
         mMoveTaskButton.setOnClickListener(null);
+
+        // Stop any focus animations
+        Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
+        mBackground.jumpToCurrentState();
     }
 
     /** Updates the resize task bar button. */
     void updateResizeTaskBarIcon(Task t) {
-        Rect display = mSsp.getWindowRect();
-        Rect taskRect = mSsp.getTaskBounds(t.key.id);
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect display = ssp.getWindowRect();
+        Rect taskRect = ssp.getTaskBounds(t.key.id);
         int resId = R.drawable.star;
         if (display.equals(taskRect) || taskRect.isEmpty()) {
             resId = R.drawable.vector_drawable_place_fullscreen;
@@ -373,16 +371,17 @@
 
     /** Notifies the associated TaskView has been focused. */
     void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) {
-        // If we are not animating the visible state, just return
-        if (!animateFocusedState) return;
-
         boolean isRunning = false;
         if (mFocusAnimator != null) {
             isRunning = mFocusAnimator.isRunning();
-            Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
         }
+        Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator);
+        mBackground.jumpToCurrentState();
 
         if (focused) {
+            // If we are not animating the visible state, just return
+            if (!animateFocusedState) return;
+
             int currentColor = mBackgroundColor;
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index f8f7052..174ff33 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -17,7 +17,7 @@
 package com.android.systemui.recents.views;
 
 import android.animation.ValueAnimator;
-import android.graphics.Rect;
+import android.graphics.RectF;
 import android.view.View;
 import android.view.ViewPropertyAnimator;
 import android.view.animation.Interpolator;
@@ -26,6 +26,7 @@
 /* The transform state for a task view */
 public class TaskViewTransform {
     public int startDelay = 0;
+    public int translationX = 0;
     public int translationY = 0;
     public float translationZ = 0;
     public float scale = 1f;
@@ -35,7 +36,7 @@
 
     // This is a window-space rect that is purely used for coordinating the animation of an app
     // window into Recents.
-    public Rect rect = new Rect();
+    public RectF rect = new RectF();
 
     public TaskViewTransform() {
         // Do nothing
@@ -43,6 +44,7 @@
 
     public TaskViewTransform(TaskViewTransform o) {
         startDelay = o.startDelay;
+        translationX = o.translationX;
         translationY = o.translationY;
         translationZ = o.translationZ;
         scale = o.scale;
@@ -52,9 +54,12 @@
         p = o.p;
     }
 
-    /** Resets the current transform */
+    /**
+     * Resets the current transform.
+     */
     public void reset() {
         startDelay = 0;
+        translationX = 0;
         translationY = 0;
         translationZ = 0;
         scale = 1f;
@@ -71,6 +76,9 @@
     public boolean hasScaleChangedFrom(float v) {
         return (Float.compare(scale, v) != 0);
     }
+    public boolean hasTranslationXChangedFrom(float v) {
+        return (Float.compare(translationX, v) != 0);
+    }
     public boolean hasTranslationYChangedFrom(float v) {
         return (Float.compare(translationY, v) != 0);
     }
@@ -87,6 +95,9 @@
             boolean requiresLayers = false;
 
             // Animate to the final state
+            if (hasTranslationXChangedFrom(v.getTranslationX())) {
+                anim.translationX(translationX);
+            }
             if (hasTranslationYChangedFrom(v.getTranslationY())) {
                 anim.translationY(translationY);
             }
@@ -117,6 +128,9 @@
                     .start();
         } else {
             // Set the changed properties
+            if (hasTranslationXChangedFrom(v.getTranslationX())) {
+                v.setTranslationX(translationX);
+            }
             if (hasTranslationYChangedFrom(v.getTranslationY())) {
                 v.setTranslationY(translationY);
             }
@@ -147,7 +161,8 @@
 
     @Override
     public String toString() {
-        return "TaskViewTransform delay: " + startDelay + " y: " + translationY + " z: " + translationZ +
+        return "TaskViewTransform delay: " + startDelay +
+                " x: " + translationX + " y: " + translationY + " z: " + translationZ +
                 " scale: " + scale + " alpha: " + alpha + " visible: " + visible + " rect: " + rect +
                 " p: " + p;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 2e3e00c..6f8cd8c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -340,7 +340,7 @@
             return;
         }
         mDark = dark;
-        if (!dark && fade) {
+        if (!dark && fade && !shouldHideBackground()) {
             if (mActivated) {
                 mBackgroundDimmed.setVisibility(View.VISIBLE);
                 mBackgroundNormal.setVisibility(View.VISIBLE);
@@ -380,7 +380,7 @@
         updateBackgroundTint();
     }
 
-    private void updateBackgroundTint() {
+    protected void updateBackgroundTint() {
         int color = getBgColor();
         int rippleColor = getRippleColor();
         if (color == mNormalColor) {
@@ -428,10 +428,12 @@
     private void fadeDimmedBackground() {
         mBackgroundDimmed.animate().cancel();
         mBackgroundNormal.animate().cancel();
-        if (mDimmed) {
-            mBackgroundDimmed.setVisibility(View.VISIBLE);
-        } else {
-            mBackgroundNormal.setVisibility(View.VISIBLE);
+        if (!shouldHideBackground()) {
+            if (mDimmed) {
+                mBackgroundDimmed.setVisibility(View.VISIBLE);
+            } else {
+                mBackgroundNormal.setVisibility(View.VISIBLE);
+            }
         }
         float startAlpha = mDimmed ? 1f : 0;
         float endAlpha = mDimmed ? 0 : 1f;
@@ -466,9 +468,9 @@
         mBackgroundAnimator.start();
     }
 
-    private void updateBackground() {
+    protected void updateBackground() {
         cancelFadeAnimations();
-        if (mDark) {
+        if (shouldHideBackground()) {
             mBackgroundDimmed.setVisibility(View.INVISIBLE);
             mBackgroundNormal.setVisibility(View.INVISIBLE);
         } else if (mDimmed) {
@@ -482,6 +484,10 @@
         }
     }
 
+    protected boolean shouldHideBackground() {
+        return mDark;
+    }
+
     private void cancelFadeAnimations() {
         if (mBackgroundAnimator != null) {
             mBackgroundAnimator.cancel();
@@ -676,7 +682,7 @@
 
     protected abstract View getContentView();
 
-    private int getBgColor() {
+    public int getBgColor() {
         if (mBgTint != 0) {
             return mBgTint;
         } else if (mShowingLegacyBackground) {
@@ -739,6 +745,10 @@
         setBelowSpeedBump(false);
     }
 
+    public boolean hasSameBgColor(ActivatableNotificationView otherView) {
+        return getBgColor() == otherView.getBgColor();
+    }
+
     public interface OnActivatedListener {
         void onActivated(ActivatableNotificationView view);
         void onActivationReset(ActivatableNotificationView view);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8938669..1e038c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -217,7 +217,7 @@
 
     private boolean mDeviceProvisioned = false;
 
-    private RecentsComponent mRecents;
+    protected RecentsComponent mRecents;
 
     protected int mZenMode;
 
@@ -891,8 +891,7 @@
     private void bindGuts(ExpandableNotificationRow row) {
         row.inflateGuts();
         final StatusBarNotification sbn = row.getStatusBarNotification();
-        PackageManager pmUser = getPackageManagerForUser(
-                sbn.getUser().getIdentifier());
+        PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
         final View guts = row.getGuts();
         final String pkg = sbn.getPackageName();
@@ -1270,25 +1269,27 @@
     }
 
     protected boolean inflateViews(Entry entry, ViewGroup parent) {
-        PackageManager pmUser = getPackageManagerForUser(
+        PackageManager pmUser = getPackageManagerForUser(mContext,
                 entry.notification.getUser().getIdentifier());
 
         int maxHeight = mRowMaxHeight;
         final StatusBarNotification sbn = entry.notification;
-        RemoteViews contentView = sbn.getNotification().contentView;
-        RemoteViews bigContentView = sbn.getNotification().bigContentView;
-        RemoteViews headsUpContentView = sbn.getNotification().headsUpContentView;
+        entry.cacheContentViews(mContext, null);
+
+        final RemoteViews contentView = entry.cachedContentView;
+        final RemoteViews bigContentView = entry.cachedBigContentView;
+        final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+        final RemoteViews publicContentView = entry.cachedPublicContentView;
 
         if (contentView == null) {
+            Log.v(TAG, "no contentView for: " + sbn.getNotification());
             return false;
         }
 
         if (DEBUG) {
-            Log.v(TAG, "publicNotification: " + sbn.getNotification().publicVersion);
+            Log.v(TAG, "publicContentView: " + publicContentView);
         }
 
-        Notification publicNotification = sbn.getNotification().publicVersion;
-
         ExpandableNotificationRow row;
 
         // Stash away previous user expansion state so we can restore it at
@@ -1377,9 +1378,9 @@
 
         // now the public version
         View publicViewLocal = null;
-        if (publicNotification != null) {
+        if (publicContentView != null) {
             try {
-                publicViewLocal = publicNotification.contentView.apply(
+                publicViewLocal = publicContentView.apply(
                         sbn.getPackageContext(mContext),
                         contentContainerPublic, mOnClickHandler);
 
@@ -1500,7 +1501,7 @@
             row.setUserExpanded(userExpanded);
         }
         row.setUserLocked(userLocked);
-        row.setStatusBarNotification(entry.notification);
+        row.setEntry(entry);
         applyRemoteInput(entry);
         return true;
     }
@@ -1537,30 +1538,9 @@
             }
 
             if (viableAction != null) {
-                Notification stripped = n.clone();
-                Notification.Builder.stripForDelivery(stripped);
-                stripped.extras.putBoolean("android.rebuild", true);
-                stripped.actions = new Notification.Action[] { viableAction };
-                stripped.extras.putBoolean("android.rebuild.contentView", true);
-                stripped.contentView = null;
-                stripped.extras.putBoolean("android.rebuild.bigView", true);
-                stripped.bigContentView = null;
-                stripped.extras.putBoolean("android.rebuild.hudView", true);
-                stripped.headsUpContentView = null;
-
-                stripped.extras.putParcelable(Notification.EXTRA_LARGE_ICON,
-                        stripped.getLargeIcon());
-                if (SystemProperties.getBoolean("debug.strip_third_line", false)) {
-                    stripped.extras.putCharSequence(Notification.EXTRA_INFO_TEXT, null);
-                    stripped.extras.putCharSequence(Notification.EXTRA_SUMMARY_TEXT, null);
-                }
-
-                Notification rebuilt = Notification.Builder.rebuild(mContext, stripped);
-
-                n.actions = rebuilt.actions;
-                n.bigContentView = rebuilt.bigContentView;
-                n.headsUpContentView = rebuilt.headsUpContentView;
-                n.publicVersion = rebuilt.publicVersion;
+                Notification.Builder rebuilder = Notification.Builder.recoverBuilder(mContext, n);
+                rebuilder.setActions(viableAction);
+                rebuilder.build(); // will rewrite n
             }
         }
     }
@@ -1949,27 +1929,29 @@
         for (int i = 0; i < N; i++) {
             NotificationData.Entry entry = activeNotifications.get(i);
             if (onKeyguard) {
-                entry.row.setExpansionDisabled(true);
+                entry.row.setOnKeyguard(true);
             } else {
-                entry.row.setExpansionDisabled(false);
-                if (!entry.row.isUserLocked()) {
-                    boolean top = (i == 0);
-                    entry.row.setSystemExpanded(top);
-                }
+                entry.row.setOnKeyguard(false);
+                boolean top = (i == 0);
+                entry.row.setSystemExpanded(top);
             }
-            boolean isInvisibleChild = !mGroupManager.isVisible(entry.notification);
+            boolean childNotification = mGroupManager.isChildInGroupWithSummary(entry.notification);
+            boolean childWithVisibleSummary = childNotification
+                    && mGroupManager.getGroupSummary(entry.notification).getVisibility()
+                    == View.VISIBLE;
             boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
             if ((isLockscreenPublicMode() && !mShowLockscreenNotifications) ||
                     (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
-                            || !showOnKeyguard || isInvisibleChild))) {
+                            && !childWithVisibleSummary
+                            || !showOnKeyguard))) {
                 entry.row.setVisibility(View.GONE);
-                if (onKeyguard && showOnKeyguard && !isInvisibleChild) {
+                if (onKeyguard && showOnKeyguard && !childNotification) {
                     mKeyguardIconOverflowContainer.getIconsView().addNotification(entry);
                 }
             } else {
                 boolean wasGone = entry.row.getVisibility() == View.GONE;
                 entry.row.setVisibility(View.VISIBLE);
-                if (!isInvisibleChild) {
+                if (!childNotification) {
                     if (wasGone) {
                         // notify the scroller of a child addition
                         mStackScroller.generateAddAnimation(entry.row, true /* fromMoreCard */);
@@ -2034,12 +2016,15 @@
         }
 
         Notification n = notification.getNotification();
-        if (DEBUG) {
-            logUpdate(entry, n);
-        }
-        boolean applyInPlace = shouldApplyInPlace(entry, n);
+
+        boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification());
         boolean shouldInterrupt = shouldInterrupt(entry, notification);
         boolean alertAgain = alertAgain(entry, n);
+        if (DEBUG) {
+            Log.d(TAG, "applyInPlace=" + applyInPlace
+                    + " shouldInterrupt=" + shouldInterrupt
+                    + " alertAgain=" + alertAgain);
+        }
 
         entry.notification = notification;
         mGroupManager.onEntryUpdated(entry, entry.notification);
@@ -2104,101 +2089,32 @@
     protected abstract void updateHeadsUp(String key, Entry entry, boolean shouldInterrupt,
             boolean alertAgain);
 
-    private void logUpdate(Entry oldEntry, Notification n) {
-        StatusBarNotification oldNotification = oldEntry.notification;
-        Log.d(TAG, "old notification: when=" + oldNotification.getNotification().when
-                + " ongoing=" + oldNotification.isOngoing()
-                + " expanded=" + oldEntry.getContentView()
-                + " contentView=" + oldNotification.getNotification().contentView
-                + " bigContentView=" + oldNotification.getNotification().bigContentView
-                + " publicView=" + oldNotification.getNotification().publicVersion
-                + " rowParent=" + oldEntry.row.getParent());
-        Log.d(TAG, "new notification: when=" + n.when
-                + " ongoing=" + oldNotification.isOngoing()
-                + " contentView=" + n.contentView
-                + " bigContentView=" + n.bigContentView
-                + " publicView=" + n.publicVersion);
-    }
-
-    /**
-     * @return whether we can just reapply the RemoteViews from a notification in-place when it is
-     * updated
-     */
-    private boolean shouldApplyInPlace(Entry entry, Notification n) {
-        StatusBarNotification oldNotification = entry.notification;
-        // XXX: modify when we do something more intelligent with the two content views
-        final RemoteViews oldContentView = oldNotification.getNotification().contentView;
-        final RemoteViews contentView = n.contentView;
-        final RemoteViews oldBigContentView = oldNotification.getNotification().bigContentView;
-        final RemoteViews bigContentView = n.bigContentView;
-        final RemoteViews oldHeadsUpContentView
-                = oldNotification.getNotification().headsUpContentView;
-        final RemoteViews headsUpContentView = n.headsUpContentView;
-        final Notification oldPublicNotification = oldNotification.getNotification().publicVersion;
-        final RemoteViews oldPublicContentView = oldPublicNotification != null
-                ? oldPublicNotification.contentView : null;
-        final Notification publicNotification = n.publicVersion;
-        final RemoteViews publicContentView = publicNotification != null
-                ? publicNotification.contentView : null;
-        boolean contentsUnchanged = entry.getContentView() != null
-                && contentView.getPackage() != null
-                && oldContentView.getPackage() != null
-                && oldContentView.getPackage().equals(contentView.getPackage())
-                && oldContentView.getLayoutId() == contentView.getLayoutId();
-        // large view may be null
-        boolean bigContentsUnchanged =
-                (entry.getExpandedContentView() == null && bigContentView == null)
-                || ((entry.getExpandedContentView() != null && bigContentView != null)
-                    && bigContentView.getPackage() != null
-                    && oldBigContentView.getPackage() != null
-                    && oldBigContentView.getPackage().equals(bigContentView.getPackage())
-                    && oldBigContentView.getLayoutId() == bigContentView.getLayoutId());
-        boolean headsUpContentsUnchanged =
-                (oldHeadsUpContentView == null && headsUpContentView == null)
-                || ((oldHeadsUpContentView != null && headsUpContentView != null)
-                    && headsUpContentView.getPackage() != null
-                    && oldHeadsUpContentView.getPackage() != null
-                    && oldHeadsUpContentView.getPackage().equals(headsUpContentView.getPackage())
-                    && oldHeadsUpContentView.getLayoutId() == headsUpContentView.getLayoutId());
-        boolean publicUnchanged  =
-                (oldPublicContentView == null && publicContentView == null)
-                || ((oldPublicContentView != null && publicContentView != null)
-                        && publicContentView.getPackage() != null
-                        && oldPublicContentView.getPackage() != null
-                        && oldPublicContentView.getPackage().equals(publicContentView.getPackage())
-                        && oldPublicContentView.getLayoutId() == publicContentView.getLayoutId());
-        return contentsUnchanged && bigContentsUnchanged && headsUpContentsUnchanged
-                && publicUnchanged;
-    }
-
-    private void updateNotificationViews(Entry entry, StatusBarNotification notification) {
-        final RemoteViews contentView = notification.getNotification().contentView;
-        final RemoteViews bigContentView = notification.getNotification().bigContentView;
-        final RemoteViews headsUpContentView = notification.getNotification().headsUpContentView;
-        final Notification publicVersion = notification.getNotification().publicVersion;
-        final RemoteViews publicContentView = publicVersion != null ? publicVersion.contentView
-                : null;
+    private void updateNotificationViews(Entry entry, StatusBarNotification sbn) {
+        final RemoteViews contentView = entry.cachedContentView;
+        final RemoteViews bigContentView = entry.cachedBigContentView;
+        final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
+        final RemoteViews publicContentView = entry.cachedPublicContentView;
 
         // Reapply the RemoteViews
         contentView.reapply(mContext, entry.getContentView(), mOnClickHandler);
         if (bigContentView != null && entry.getExpandedContentView() != null) {
-            bigContentView.reapply(notification.getPackageContext(mContext),
+            bigContentView.reapply(sbn.getPackageContext(mContext),
                     entry.getExpandedContentView(),
                     mOnClickHandler);
         }
         View headsUpChild = entry.getHeadsUpContentView();
         if (headsUpContentView != null && headsUpChild != null) {
-            headsUpContentView.reapply(notification.getPackageContext(mContext),
+            headsUpContentView.reapply(sbn.getPackageContext(mContext),
                     headsUpChild, mOnClickHandler);
         }
         if (publicContentView != null && entry.getPublicContentView() != null) {
-            publicContentView.reapply(notification.getPackageContext(mContext),
+            publicContentView.reapply(sbn.getPackageContext(mContext),
                     entry.getPublicContentView(), mOnClickHandler);
         }
         // update the contentIntent
-        mNotificationClicker.register(entry.row, notification);
+        mNotificationClicker.register(entry.row, sbn);
 
-        entry.row.setStatusBarNotification(notification);
+        entry.row.setEntry(entry);
         entry.row.notifyContentUpdated();
         entry.row.resetHeight();
 
@@ -2292,15 +2208,15 @@
      * @return a PackageManger for userId or if userId is < 0 (USER_ALL etc) then
      *         return PackageManager for mContext
      */
-    protected PackageManager getPackageManagerForUser(int userId) {
-        Context contextForUser = mContext;
+    public static PackageManager getPackageManagerForUser(Context context, int userId) {
+        Context contextForUser = context;
         // UserHandle defines special userId as negative values, e.g. USER_ALL
         if (userId >= 0) {
             try {
                 // Create a context for the correct user so if a package isn't installed
                 // for user 0 we can still load information about the package.
                 contextForUser =
-                        mContext.createPackageContextAsUser(mContext.getPackageName(),
+                        context.createPackageContextAsUser(context.getPackageName(),
                         Context.CONTEXT_RESTRICTED,
                         new UserHandle(userId));
             } catch (NameNotFoundException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 7b0a44f..14051916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -134,6 +134,8 @@
                         (int) (y - mInitialTouchY))) {
                     if (mStartingChild == null) {
                         mDragDownCallback.setEmptyDragAmount(0f);
+                    } else {
+                        mCallback.setUserLockedChild(mStartingChild, false);
                     }
                     mDraggingDown = false;
                 } else {
@@ -175,15 +177,16 @@
             overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
             rubberband -= overshoot;
         }
-        child.setContentHeight((int) (child.getMinHeight() + rubberband));
+        child.setActualHeight((int) (child.getMinHeight() + rubberband));
     }
 
     private void cancelExpansion(final ExpandableView child) {
-        if (child.getContentHeight() == child.getMinHeight()) {
+        if (child.getActualHeight() == child.getMinHeight()) {
+            mCallback.setUserLockedChild(child, false);
             return;
         }
-        ObjectAnimator anim = ObjectAnimator.ofInt(child, "contentHeight",
-                child.getContentHeight(), child.getMinHeight());
+        ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
+                child.getActualHeight(), child.getMinHeight());
         anim.setInterpolator(mInterpolator);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 33f21ff..3603900 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -16,9 +16,7 @@
 
 package com.android.systemui.statusbar;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.app.Notification;
 import android.content.Context;
 import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.AnimationDrawable;
@@ -36,8 +34,8 @@
 
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.statusbar.notification.NotificationHeaderView;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
 import com.android.systemui.statusbar.stack.StackScrollState;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
@@ -73,9 +71,9 @@
     private boolean mIsSystemExpanded;
 
     /**
-     * Whether the notification expansion is disabled. This is the case on Keyguard.
+     * Whether the notification is on the keyguard and the expansion is disabled.
      */
-    private boolean mExpansionDisabled;
+    private boolean mOnKeyguard;
 
     private NotificationContentView mPublicLayout;
     private NotificationContentView mPrivateLayout;
@@ -90,31 +88,23 @@
     private StatusBarNotification mStatusBarNotification;
     private boolean mIsHeadsUp;
     private boolean mLastChronometerRunning = true;
-    private View mExpandButton;
-    private View mExpandButtonDivider;
-    private ViewStub mExpandButtonStub;
+    private NotificationHeaderView mNotificationHeader;
+    private ViewStub mNotificationHeaderStub;
     private ViewStub mChildrenContainerStub;
     private NotificationGroupManager mGroupManager;
-    private View mExpandButtonContainer;
     private boolean mChildrenExpanded;
+    private boolean mIsSummaryWithChildren;
     private NotificationChildrenContainer mChildrenContainer;
-    private ValueAnimator mChildExpandAnimator;
-    private float mChildrenExpandProgress;
-    private float mExpandButtonStart;
     private ViewStub mGutsStub;
-    private boolean mHasExpandAction;
+    private boolean mHasNotificationHeader;
     private boolean mIsSystemChildExpanded;
     private boolean mIsPinned;
-    private OnClickListener mExpandClickListener = new OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            mGroupManager.setGroupExpanded(mStatusBarNotification,
-                    !mChildrenExpanded);
-        }
-    };
     private FalsingManager mFalsingManager;
 
     private boolean mJustClicked;
+    private NotificationData.Entry mEntry;
+    private boolean mShowNoBackground;
+    private ExpandableNotificationRow mNotificationParent;
 
     public NotificationContentView getPrivateLayout() {
         return mPrivateLayout;
@@ -171,10 +161,11 @@
         }
     }
 
-    public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
+    private void setStatusBarNotification(StatusBarNotification statusBarNotification) {
         mStatusBarNotification = statusBarNotification;
+        mPrivateLayout.setStatusBarNotification(statusBarNotification);
         updateVetoButton();
-        updateExpandButton();
+        onChildrenCountChanged();
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -196,6 +187,7 @@
 
     public void setGroupManager(NotificationGroupManager groupManager) {
         mGroupManager = groupManager;
+        mPrivateLayout.setGroupManager(groupManager);
     }
 
     public void addChildNotification(ExpandableNotificationRow row) {
@@ -213,12 +205,45 @@
             mChildrenContainerStub.inflate();
         }
         mChildrenContainer.addNotification(row, childIndex);
+        onChildrenCountChanged();
+        row.setIsChildInGroup(true, this);
     }
 
     public void removeChildNotification(ExpandableNotificationRow row) {
         if (mChildrenContainer != null) {
             mChildrenContainer.removeNotification(row);
         }
+        onChildrenCountChanged();
+        row.setIsChildInGroup(false, null);
+    }
+
+    public boolean isChildInGroup() {
+        return mNotificationParent != null;
+    }
+
+    public ExpandableNotificationRow getNotificationParent() {
+        return mNotificationParent;
+    }
+
+    /**
+     * @param isChildInGroup Is this notification now in a group
+     * @param parent the new parent notification
+     */
+    public void setIsChildInGroup(boolean isChildInGroup, ExpandableNotificationRow parent) {;
+        boolean childInGroup = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && isChildInGroup;
+        mNotificationParent = childInGroup ? parent : null;
+        mPrivateLayout.setIsChildInGroup(childInGroup);
+        updateNoBackgroundState();
+    }
+
+    @Override
+    protected boolean shouldHideBackground() {
+        return super.shouldHideBackground() || mShowNoBackground;
+    }
+
+    @Override
+    public boolean isSummaryWithChildren() {
+        return mIsSummaryWithChildren;
     }
 
     @Override
@@ -230,6 +255,13 @@
         return mChildrenContainer == null ? null : mChildrenContainer.getNotificationChildren();
     }
 
+    public int getNumberOfNotificationChildren() {
+        if (mChildrenContainer == null) {
+            return 0;
+        }
+        return mChildrenContainer.getNotificationChildren().size();
+    }
+
     /**
      * Apply the order given in the list to the children.
      *
@@ -241,34 +273,34 @@
     }
 
     public void getChildrenStates(StackScrollState resultState) {
-        if (mChildrenExpanded) {
+        if (mIsSummaryWithChildren) {
             StackViewState parentState = resultState.getViewStateForView(this);
             mChildrenContainer.getState(resultState, parentState);
         }
     }
 
     public void applyChildrenState(StackScrollState state) {
-        if (mChildrenExpanded) {
+        if (mIsSummaryWithChildren) {
             mChildrenContainer.applyState(state);
         }
     }
 
     public void prepareExpansionChanged(StackScrollState state) {
-        if (mChildrenExpanded) {
+        if (mIsSummaryWithChildren) {
             mChildrenContainer.prepareExpansionChanged(state);
         }
     }
 
     public void startChildAnimation(StackScrollState finalState,
             StackStateAnimator stateAnimator, boolean withDelays, long delay, long duration) {
-        if (mChildrenExpanded) {
+        if (mIsSummaryWithChildren) {
             mChildrenContainer.startAnimationToState(finalState, stateAnimator, withDelays, delay,
                     duration);
         }
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
-        if (!mChildrenExpanded) {
+        if (!mIsSummaryWithChildren || !mChildrenExpanded) {
             return this;
         } else {
             ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
@@ -280,15 +312,6 @@
         return mGuts;
     }
 
-    protected int calculateContentHeightFromActualHeight(int actualHeight) {
-        int realActualHeight = actualHeight;
-        if (hasBottomDecor()) {
-            realActualHeight -= getBottomDecorHeight();
-        }
-        realActualHeight = Math.max(getMinHeight(), realActualHeight);
-        return realActualHeight;
-    }
-
     /**
      * Set this notification to be pinned to the top if {@link #isHeadsUp()} is true. By doing this
      * the notification will be rendered on top of the screen.
@@ -358,6 +381,24 @@
         }
     }
 
+    public void setEntry(NotificationData.Entry entry) {
+        mEntry = entry;
+        setStatusBarNotification(entry.notification);
+    }
+
+    public CharSequence getSubText() {
+        Notification notification = mStatusBarNotification.getNotification();
+        CharSequence subText = notification.extras.getCharSequence(Notification.EXTRA_SUMMARY_TEXT);
+        if (subText == null) {
+            subText = notification.extras.getCharSequence(Notification.EXTRA_SUB_TEXT);
+        }
+        return subText;
+    }
+
+    public void setContentSubTextVisible(boolean visible) {
+        mPrivateLayout.setSubTextVisible(visible);
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
@@ -383,7 +424,7 @@
         mSensitive = false;
         mShowingPublicInitialized = false;
         mIsSystemExpanded = false;
-        mExpansionDisabled = false;
+        mOnKeyguard = false;
         mPublicLayout.reset(mIsHeadsUp);
         mPrivateLayout.reset(mIsHeadsUp);
         resetHeight();
@@ -421,15 +462,13 @@
                 mGutsStub = null;
             }
         });
-        mExpandButtonStub = (ViewStub) findViewById(R.id.more_button_stub);
-        mExpandButtonStub.setOnInflateListener(new ViewStub.OnInflateListener() {
-
+        mNotificationHeaderStub = (ViewStub) findViewById(R.id.notification_header_stub);
+        mNotificationHeaderStub.setOnInflateListener(new ViewStub.OnInflateListener() {
             @Override
             public void onInflate(ViewStub stub, View inflated) {
-                mExpandButtonContainer = inflated;
-                mExpandButton = inflated.findViewById(R.id.notification_expand_button);
-                mExpandButtonDivider = inflated.findViewById(R.id.notification_expand_divider);
-                mExpandButtonContainer.setOnClickListener(mExpandClickListener);
+                mNotificationHeader = (NotificationHeaderView) inflated;
+                mNotificationHeader.setGroupManager(mGroupManager);
+                mNotificationHeader.bind(mEntry);
             }
         });
         mChildrenContainerStub = (ViewStub) findViewById(R.id.child_container_stub);
@@ -438,8 +477,7 @@
             @Override
             public void onInflate(ViewStub stub, View inflated) {
                 mChildrenContainer = (NotificationChildrenContainer) inflated;
-                mChildrenContainer.setCollapseClickListener(mExpandClickListener);
-                updateChildrenVisibility(false);
+                mChildrenContainer.setNotificationParent(ExpandableNotificationRow.this);
             }
         });
         mVetoButton = findViewById(R.id.veto);
@@ -455,48 +493,8 @@
         if (mChildrenContainer == null) {
             return;
         }
-        if (mChildExpandAnimator != null) {
-            mChildExpandAnimator.cancel();
-        }
-        float targetProgress = mChildrenExpanded ? 1.0f : 0.0f;
-        if (animated) {
-            if (mChildrenExpanded) {
-                mChildrenContainer.setVisibility(VISIBLE);
-            }
-            mExpandButtonStart = mExpandButtonContainer.getTranslationY();
-            mChildExpandAnimator = ValueAnimator.ofFloat(mChildrenExpandProgress, targetProgress);
-            mChildExpandAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    setChildrenExpandProgress((float) animation.getAnimatedValue());
-                }
-            });
-            mChildExpandAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mChildExpandAnimator = null;
-                    if (!mChildrenExpanded) {
-                        mChildrenContainer.setVisibility(INVISIBLE);
-                    }
-                }
-            });
-            mChildExpandAnimator.setInterpolator(mLinearInterpolator);
-            mChildExpandAnimator.setDuration(
-                    StackStateAnimator.ANIMATION_DURATION_EXPAND_CLICKED);
-            mChildExpandAnimator.start();
-        } else {
-            setChildrenExpandProgress(targetProgress);
-            mChildrenContainer.setVisibility(mChildrenExpanded ? VISIBLE : INVISIBLE);
-        }
-    }
-
-    private void setChildrenExpandProgress(float progress) {
-        mChildrenExpandProgress = progress;
-        updateExpandButtonAppearance();
-        NotificationContentView showingLayout = getShowingLayout();
-        float alpha = 1.0f - mChildrenExpandProgress;
-        alpha = PhoneStatusBar.ALPHA_OUT.getInterpolation(alpha);
-        showingLayout.setAlpha(alpha);
+        mChildrenContainer.setVisibility(mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
+        mPrivateLayout.setVisibility(!mIsSummaryWithChildren ? VISIBLE : INVISIBLE);
     }
 
     @Override
@@ -528,6 +526,9 @@
     }
 
     public boolean isExpandable() {
+        if (mIsSummaryWithChildren && !mShowingPublic) {
+            return !mChildrenExpanded;
+        }
         return mExpandable;
     }
 
@@ -552,7 +553,21 @@
      * @param userExpanded whether the user wants this notification to be expanded
      */
     public void setUserExpanded(boolean userExpanded) {
+        setUserExpanded(userExpanded, false /* allowChildExpansion */);
+    }
+
+    /**
+     * Set this notification to be expanded by the user
+     *
+     * @param userExpanded whether the user wants this notification to be expanded
+     * @param allowChildExpansion whether a call to this method allows expanding children
+     */
+    public void setUserExpanded(boolean userExpanded, boolean allowChildExpansion) {
         mFalsingManager.setNotificationExpanded();
+        if (mIsSummaryWithChildren && !mShowingPublic && allowChildExpansion) {
+            mGroupManager.setGroupExpanded(mStatusBarNotification, userExpanded);
+            return;
+        }
         if (userExpanded && !mExpandable) return;
         final boolean wasExpanded = isExpanded();
         mHasUserChangedExpansion = true;
@@ -591,16 +606,19 @@
             mIsSystemExpanded = expand;
             notifyHeightChanged(false /* needsAnimation */);
             logExpansionEvent(false, wasExpanded);
+            if (mChildrenContainer != null) {
+                mChildrenContainer.updateGroupOverflow();
+            }
         }
     }
 
     /**
-     * @param expansionDisabled whether to prevent notification expansion
+     * @param onKeyguard whether to prevent notification expansion
      */
-    public void setExpansionDisabled(boolean expansionDisabled) {
-        if (expansionDisabled != mExpansionDisabled) {
+    public void setOnKeyguard(boolean onKeyguard) {
+        if (onKeyguard != mOnKeyguard) {
             final boolean wasExpanded = isExpanded();
-            mExpansionDisabled = expansionDisabled;
+            mOnKeyguard = onKeyguard;
             logExpansionEvent(false, wasExpanded);
             if (wasExpanded != isExpanded()) {
                 notifyHeightChanged(false  /* needsAnimation */);
@@ -621,9 +639,9 @@
     public void applyExpansionToLayout() {
         boolean expand = isExpanded();
         if (expand && mExpandable) {
-            setContentHeight(mMaxExpandHeight);
+            setActualHeight(mMaxExpandHeight);
         } else {
-            setContentHeight(mRowMinHeight);
+            setActualHeight(mRowMinHeight);
         }
     }
 
@@ -633,34 +651,43 @@
             return getActualHeight();
         }
         boolean inExpansionState = isExpanded();
-        int maxContentHeight;
         if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return mRowMinHeight;
+        } else if (mIsSummaryWithChildren && !mOnKeyguard) {
+            return mChildrenContainer.getIntrinsicHeight()
+                    + mNotificationHeader.getHeight();
         } else if (mIsHeadsUp) {
             if (inExpansionState) {
-                maxContentHeight = Math.max(mMaxExpandHeight, mHeadsUpHeight);
+                return Math.max(mMaxExpandHeight, mHeadsUpHeight);
             } else {
-                maxContentHeight = Math.max(mRowMinHeight, mHeadsUpHeight);
+                return Math.max(mRowMinHeight, mHeadsUpHeight);
             }
-        } else if ((!inExpansionState && !mChildrenExpanded)) {
-            maxContentHeight = mRowMinHeight;
-        } else if (mChildrenExpanded) {
-            maxContentHeight = mChildrenContainer.getIntrinsicHeight();
+        } else if (!inExpansionState || (isChildInGroup() && !isGroupExpanded())) {
+            return getMinHeight();
         } else {
-            maxContentHeight = getMaxExpandHeight();
+            return getMaxExpandHeight();
         }
-        return maxContentHeight + getBottomDecorHeight();
     }
 
-    @Override
-    protected boolean hasBottomDecor() {
-        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
-                && !mIsHeadsUp && mGroupManager.hasGroupChildren(mStatusBarNotification);
+    private boolean isGroupExpanded() {
+        return mGroupManager.isGroupExpanded(mStatusBarNotification);
     }
 
-    @Override
-    protected boolean canHaveBottomDecor() {
-        return BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS && !mIsHeadsUp;
+    /**
+     * @return whether this view has a header on the top of the content
+     */
+    private boolean hasNotificationHeader() {
+        return mIsSummaryWithChildren;
+    }
+
+    private void onChildrenCountChanged() {
+        mIsSummaryWithChildren  = BaseStatusBar.ENABLE_CHILD_NOTIFICATIONS
+                && mGroupManager.hasGroupChildren(mStatusBarNotification);
+        if (mIsSummaryWithChildren && mChildrenContainer == null) {
+            mChildrenContainerStub.inflate();
+        }
+        updateNotificationHeader();
+        updateChildrenVisibility(true);
     }
 
     /**
@@ -671,8 +698,8 @@
      *
      * @return whether the view state is currently expanded.
      */
-    private boolean isExpanded() {
-        return !mExpansionDisabled
+    public boolean isExpanded() {
+        return !mOnKeyguard
                 && (!hasUserChangedExpansion() && (isSystemExpanded() || isSystemChildExpanded())
                 || isUserExpanded());
     }
@@ -696,15 +723,6 @@
         mWasReset = false;
     }
 
-    @Override
-    protected boolean isChildInvisible(View child) {
-
-        // We don't want to layout the ChildrenContainer if this is a heads-up view, otherwise the
-        // view will get too high and the shadows will be off.
-        boolean isInvisibleChildContainer = child == mChildrenContainer && mIsHeadsUp;
-        return super.isChildInvisible(child) || isInvisibleChildContainer;
-    }
-
     private void updateMaxHeights() {
         int intrinsicBefore = getIntrinsicHeight();
         View expandedChild = mPrivateLayout.getExpandedChild();
@@ -747,7 +765,8 @@
             mPublicLayout.setAlpha(1f);
             mPrivateLayout.setAlpha(1f);
             mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
-            mPrivateLayout.setVisibility(mShowingPublic ? View.INVISIBLE : View.VISIBLE);
+            mPrivateLayout.setVisibility(!mShowingPublic && !mIsSummaryWithChildren ? View.VISIBLE
+                    : View.INVISIBLE);
         } else {
             animateShowingPublic(delay, duration);
         }
@@ -787,105 +806,28 @@
 
     public void setChildrenExpanded(boolean expanded, boolean animate) {
         mChildrenExpanded = expanded;
-        updateChildrenVisibility(animate);
+        if (mChildrenContainer != null) {
+            mChildrenContainer.setChildrenExpanded(expanded);
+        }
     }
 
-    public void updateExpandButton() {
-        boolean hasExpand = hasBottomDecor();
-        if (hasExpand != mHasExpandAction) {
-            if (hasExpand) {
-                if (mExpandButtonContainer == null) {
-                    mExpandButtonStub.inflate();
+    public void updateNotificationHeader() {
+        boolean hasHeader = hasNotificationHeader();
+        if (hasHeader != mHasNotificationHeader) {
+            if (hasHeader) {
+                if (mNotificationHeader == null) {
+                    mNotificationHeaderStub.inflate();
                 }
-                mExpandButtonContainer.setVisibility(View.VISIBLE);
-                updateExpandButtonAppearance();
-                updateExpandButtonColor();
-            } else if (mExpandButtonContainer != null) {
-                mExpandButtonContainer.setVisibility(View.GONE);
+                mNotificationHeader.setVisibility(View.VISIBLE);
+            } else if (mNotificationHeader != null) {
+                mNotificationHeader.setVisibility(View.GONE);
             }
             notifyHeightChanged(true  /* needsAnimation */);
         }
-        mHasExpandAction = hasExpand;
-    }
-
-    private void updateExpandButtonAppearance() {
-        if (mExpandButtonContainer == null) {
-            return;
+        if (hasHeader) {
+            mNotificationHeader.bind(mEntry);
         }
-        float expandButtonAlpha = 0.0f;
-        float expandButtonTranslation = 0.0f;
-        float containerTranslation = 0.0f;
-        int minHeight = getMinHeight();
-        if (!mChildrenExpanded || mChildExpandAnimator != null) {
-            int expandActionHeight = getBottomDecorHeight();
-            int translationY = getActualHeight() - expandActionHeight;
-            if (translationY > minHeight) {
-                containerTranslation = translationY;
-                expandButtonAlpha = 1.0f;
-                expandButtonTranslation = 0.0f;
-            } else {
-                containerTranslation = minHeight;
-                float progress = expandActionHeight != 0
-                        ? (minHeight - translationY) / (float) expandActionHeight
-                        : 1.0f;
-                expandButtonTranslation = -progress * expandActionHeight * 0.7f;
-                float alphaProgress = Math.min(progress / 0.7f, 1.0f);
-                alphaProgress = PhoneStatusBar.ALPHA_OUT.getInterpolation(alphaProgress);
-                expandButtonAlpha = 1.0f - alphaProgress;
-            }
-        }
-        if (mChildExpandAnimator != null || mChildrenExpanded) {
-            expandButtonAlpha = (1.0f - mChildrenExpandProgress)
-                    * expandButtonAlpha;
-            expandButtonTranslation = (1.0f - mChildrenExpandProgress)
-                    * expandButtonTranslation;
-            float newTranslation = -getBottomDecorHeight();
-
-            // We don't want to take the actual height of the view as this is already
-            // interpolated by a custom interpolator leading to a confusing animation. We want
-            // to have a stable end value to interpolate in between
-            float collapsedHeight = !mChildrenExpanded
-                    ? Math.max(StackStateAnimator.getFinalActualHeight(this)
-                            - getBottomDecorHeight(), minHeight)
-                    : mExpandButtonStart;
-            float translationProgress = mFastOutSlowInInterpolator.getInterpolation(
-                    mChildrenExpandProgress);
-            containerTranslation = (1.0f - translationProgress) * collapsedHeight
-                    + translationProgress * newTranslation;
-        }
-        mExpandButton.setAlpha(expandButtonAlpha);
-        mExpandButtonDivider.setAlpha(expandButtonAlpha);
-        mExpandButton.setTranslationY(expandButtonTranslation);
-        mExpandButtonContainer.setTranslationY(containerTranslation);
-        NotificationContentView showingLayout = getShowingLayout();
-        float layoutTranslation =
-                mExpandButtonContainer.getTranslationY() - showingLayout.getContentHeight();
-        layoutTranslation = Math.min(layoutTranslation, 0);
-        if (!mChildrenExpanded && mChildExpandAnimator == null) {
-            // Needed for the DragDownHelper in order not to jump there, as the position
-            // can be negative for a short time.
-            layoutTranslation = 0;
-        }
-        showingLayout.setTranslationY(layoutTranslation);
-        if (mChildrenContainer != null) {
-            mChildrenContainer.setTranslationY(
-                    mExpandButtonContainer.getTranslationY() + getBottomDecorHeight());
-        }
-    }
-
-    private void updateExpandButtonColor() {
-        // TODO: This needs some more baking, currently only the divider is colored according to
-        // the tint, but legacy black doesn't work yet perfectly for the button etc.
-        int color = getRippleColor();
-        if (color == mNormalRippleColor) {
-            color = 0;
-        }
-        if (mExpandButtonDivider != null) {
-            applyTint(mExpandButtonDivider, color);
-        }
-        if (mChildrenContainer != null) {
-            mChildrenContainer.setTintColor(color);
-        }
+        mHasNotificationHeader = hasHeader;
     }
 
     public static void applyTint(View v, int color) {
@@ -922,29 +864,41 @@
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
         super.setActualHeight(height, notifyListeners);
-        int contentHeight = calculateContentHeightFromActualHeight(height);
+        int contentHeight = Math.max(getMinHeight(), height);
         mPrivateLayout.setContentHeight(contentHeight);
         mPublicLayout.setContentHeight(contentHeight);
         if (mGuts != null) {
             mGuts.setActualHeight(height);
         }
         invalidate();
-        updateExpandButtonAppearance();
     }
 
     @Override
     public int getMaxContentHeight() {
+        if (mIsSummaryWithChildren && !mShowingPublic) {
+            return mChildrenContainer.getMaxContentHeight()
+                    + mNotificationHeader.getHeight();
+        }
         NotificationContentView showingLayout = getShowingLayout();
         return showingLayout.getMaxHeight();
     }
 
     @Override
     public int getMinHeight() {
+        if (mIsSummaryWithChildren && !mOnKeyguard) {
+            return mChildrenContainer.getMinHeight()
+                    + mNotificationHeader.getHeight();
+        }
         NotificationContentView showingLayout = getShowingLayout();
         return showingLayout.getMinHeight();
     }
 
     @Override
+    protected boolean shouldLimitViewHeight() {
+        return !mIsSummaryWithChildren;
+    }
+
+    @Override
     public void setClipTopAmount(int clipTopAmount) {
         super.setClipTopAmount(clipTopAmount);
         mPrivateLayout.setClipTopAmount(clipTopAmount);
@@ -974,6 +928,25 @@
         mPublicLayout.setShowingLegacyBackground(showing);
     }
 
+    @Override
+    protected void updateBackgroundTint() {
+        super.updateBackgroundTint();
+        updateNoBackgroundState();
+        if (mIsSummaryWithChildren) {
+            List<ExpandableNotificationRow> notificationChildren =
+                    mChildrenContainer.getNotificationChildren();
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow child = notificationChildren.get(i);
+                child.updateNoBackgroundState();
+            }
+        }
+    }
+
+    private void updateNoBackgroundState() {
+        mShowNoBackground = isChildInGroup() && hasSameBgColor(mNotificationParent);
+        updateBackground();
+    }
+
     public void setExpansionLogger(ExpansionLogger logger, String key) {
         mLogger = logger;
         mLoggingKey = key;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 71baf57..af59ac7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -33,7 +33,6 @@
  */
 public abstract class ExpandableView extends FrameLayout {
 
-    private final int mBottomDecorHeight;
     protected OnHeightChangedListener mOnHeightChangedListener;
     protected int mMaxViewHeight;
     private int mActualHeight;
@@ -50,17 +49,12 @@
         super(context, attrs);
         mMaxViewHeight = getResources().getDimensionPixelSize(
                 R.dimen.notification_max_height);
-        mBottomDecorHeight = resolveBottomDecorHeight();
-    }
-
-    protected int resolveBottomDecorHeight() {
-        return getResources().getDimensionPixelSize(
-                R.dimen.notification_bottom_decor_height);
     }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        int ownMaxHeight = mMaxViewHeight;
+        boolean limitViewHeight = shouldLimitViewHeight();
+        int ownMaxHeight = limitViewHeight ? mMaxViewHeight : Integer.MAX_VALUE;
         int heightMode = MeasureSpec.getMode(heightMeasureSpec);
         boolean hasFixedHeight = heightMode == MeasureSpec.EXACTLY;
         if (hasFixedHeight) {
@@ -72,7 +66,7 @@
         int childCount = getChildCount();
         for (int i = 0; i < childCount; i++) {
             View child = getChildAt(i);
-            if (child.getVisibility() == GONE || isChildInvisible(child)) {
+            if (child.getVisibility() == GONE) {
                 continue;
             }
             int childHeightSpec = newHeightSpec;
@@ -80,7 +74,7 @@
             if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) {
                 if (layoutParams.height >= 0) {
                     // An actual height is set
-                    childHeightSpec = layoutParams.height > ownMaxHeight
+                    childHeightSpec = layoutParams.height > ownMaxHeight && limitViewHeight
                         ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY)
                         : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
                 }
@@ -102,20 +96,20 @@
         }
         mMatchParentViews.clear();
         int width = MeasureSpec.getSize(widthMeasureSpec);
-        if (canHaveBottomDecor()) {
-            // We always account for the expandAction as well.
-            ownHeight += mBottomDecorHeight;
-        }
         setMeasuredDimension(width, ownHeight);
     }
 
+    protected boolean shouldLimitViewHeight() {
+        return true;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mActualHeightInitialized && mActualHeight == 0) {
             int initialHeight = getInitialHeight();
             if (initialHeight != 0) {
-                setContentHeight(initialHeight);
+                setActualHeight(initialHeight);
             }
         }
         updateClipping();
@@ -173,8 +167,8 @@
         }
     }
 
-    public void setContentHeight(int contentHeight) {
-        setActualHeight(contentHeight + getBottomDecorHeight(), true);
+    public void setActualHeight(int actualHeight) {
+        setActualHeight(actualHeight, true /* notifyListeners */);
     }
 
     /**
@@ -187,31 +181,6 @@
     }
 
     /**
-     * This view may have a bottom decor which will be placed below the content. If it has one, this
-     * view will be layouted higher than just the content by {@link #mBottomDecorHeight}.
-     * @return the height of the decor if it currently has one
-     */
-    public int getBottomDecorHeight() {
-        return hasBottomDecor() ? mBottomDecorHeight : 0;
-    }
-
-    /**
-     * @return whether this view may have a bottom decor at all. This will force the view to layout
-     *         itself higher than just it's content
-     */
-    protected boolean canHaveBottomDecor() {
-        return false;
-    }
-
-    /**
-     * @return whether this view has a decor view below it's content. This will make the intrinsic
-     *         height from {@link #getIntrinsicHeight()} higher as well
-     */
-    protected boolean hasBottomDecor() {
-        return false;
-    }
-
-    /**
      * @return The maximum height of this notification.
      */
     public int getMaxContentHeight() {
@@ -358,14 +327,7 @@
         outRect.top += getClipTopOptimization();
     }
 
-    public int getContentHeight() {
-        return mActualHeight - getBottomDecorHeight();
-    }
-
-    /**
-     * @return whether the given child can be ignored for layouting and measuring purposes
-     */
-    protected boolean isChildInvisible(View child) {
+    public boolean isSummaryWithChildren() {
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 86d7f4f..5aedaf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -22,6 +22,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
@@ -32,6 +33,9 @@
 import android.widget.FrameLayout;
 
 import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 
 /**
  * A frame layout containing the actual payload of the notification, including the contracted,
@@ -44,8 +48,10 @@
     private static final int VISIBLE_TYPE_CONTRACTED = 0;
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
+    private static final int VISIBLE_TYPE_SINGLELINE = 3;
 
     private final Rect mClipBounds = new Rect();
+    private final int mSingleLineHeight;
     private final int mSmallHeight;
     private final int mHeadsUpHeight;
     private final int mRoundRectRadius;
@@ -55,10 +61,12 @@
     private View mContractedChild;
     private View mExpandedChild;
     private View mHeadsUpChild;
+    private HybridNotificationView mSingleLineView;
 
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
+    private HybridNotificationViewManager mHybridViewManager;
     private int mClipTopAmount;
     private int mContentHeight;
     private int mUnrestrictedContentHeight;
@@ -68,6 +76,8 @@
     private boolean mAnimate;
     private boolean mIsHeadsUp;
     private boolean mShowingLegacyBackground;
+    private boolean mIsChildInGroup;
+    private StatusBarNotification mStatusBarNotification;
 
     private final ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
             = new ViewTreeObserver.OnPreDrawListener() {
@@ -86,10 +96,14 @@
                     mRoundRectRadius);
         }
     };
+    private NotificationGroupManager mGroupManager;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
         mFadePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
+        mSingleLineHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_single_line_height);
         mSmallHeight = getResources().getDimensionPixelSize(R.dimen.notification_min_height);
         mHeadsUpHeight = getResources().getDimensionPixelSize(R.dimen.notification_mid_height);
         mRoundRectRadius = getResources().getDimensionPixelSize(
@@ -140,6 +154,12 @@
                     MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mHeadsUpChild.getMeasuredHeight());
         }
+        if (mSingleLineView != null) {
+            int size = Math.min(maxSize, mSingleLineHeight);
+            mSingleLineView.measure(widthMeasureSpec,
+                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY));
+            maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
+        }
         int ownHeight = Math.min(maxChildHeight, maxSize);
         int width = MeasureSpec.getSize(widthMeasureSpec);
         setMeasuredDimension(width, ownHeight);
@@ -271,7 +291,15 @@
     }
 
     public int getMinHeight() {
-        return mSmallHeight;
+        if (mIsChildInGroup && !isGroupExpanded()) {
+            return mSingleLineHeight;
+        } else {
+            return mSmallHeight;
+        }
+    }
+
+    private boolean isGroupExpanded() {
+        return mGroupManager.isGroupExpanded(mStatusBarNotification);
     }
 
     public void setClipTopAmount(int clipTopAmount) {
@@ -313,6 +341,7 @@
         if (visibleType != mVisibleType || force) {
             if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
                     || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
+                    || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
                     || visibleType == VISIBLE_TYPE_CONTRACTED)) {
                 runSwitchAnimation(visibleType);
             } else {
@@ -339,6 +368,12 @@
             mHeadsUpChild.setAlpha(headsUpVisible ? 1f : 0f);
             mHeadsUpChild.setLayerType(LAYER_TYPE_NONE, null);
         }
+        if (mSingleLineView != null) {
+            boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
+            mSingleLineView.setVisibility(singleLineVisible ? View.VISIBLE : View.INVISIBLE);
+            mSingleLineView.setAlpha(singleLineVisible ? 1f : 0f);
+            mSingleLineView.setLayerType(LAYER_TYPE_NONE, null);
+        }
         setLayerType(LAYER_TYPE_NONE, null);
         updateRoundRectClipping();
     }
@@ -379,6 +414,8 @@
                 return mExpandedChild;
             case VISIBLE_TYPE_HEADSUP:
                 return mHeadsUpChild;
+            case VISIBLE_TYPE_SINGLELINE:
+                return mSingleLineView;
             default:
                 return mContractedChild;
         }
@@ -396,7 +433,9 @@
                 return VISIBLE_TYPE_EXPANDED;
             }
         } else {
-            if (mContentHeight <= mSmallHeight || noExpandedChild) {
+            if (mIsChildInGroup && !isGroupExpanded()) {
+                return VISIBLE_TYPE_SINGLELINE;
+            } else if (mContentHeight <= mSmallHeight || noExpandedChild) {
                 return VISIBLE_TYPE_CONTRACTED;
             } else {
                 return VISIBLE_TYPE_EXPANDED;
@@ -405,6 +444,7 @@
     }
 
     public void notifyContentUpdated() {
+        updateSingleLineView();
         selectLayout(false /* animate */, true /* force */);
         if (mContractedChild != null) {
             mContractedWrapper.notifyContentUpdated();
@@ -442,4 +482,37 @@
     public void setShowingLegacyBackground(boolean showing) {
         mShowingLegacyBackground = showing;
     }
+
+    public void setIsChildInGroup(boolean isChildInGroup) {
+        mIsChildInGroup = isChildInGroup;
+        updateSingleLineView();
+    }
+
+    public void setStatusBarNotification(StatusBarNotification statusBarNotification) {
+        mStatusBarNotification = statusBarNotification;
+        updateSingleLineView();
+    }
+
+    private void updateSingleLineView() {
+        if (mIsChildInGroup) {
+            mSingleLineView = mHybridViewManager.bindFromNotification(
+                    mSingleLineView, mStatusBarNotification.getNotification());
+        }
+    }
+
+    public void setSubTextVisible(boolean visible) {
+        if (mExpandedChild != null) {
+            mExpandedWrapper.setSubTextVisible(visible);
+        }
+        if (mContractedChild != null) {
+            mContractedWrapper.setSubTextVisible(visible);
+        }
+        if (mHeadsUpChild != null) {
+            mHeadsUpWrapper.setSubTextVisible(visible);
+        }
+    }
+
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        mGroupManager = groupManager;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index aedae52..6a90d8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.app.Notification;
+import android.content.Context;
 import android.os.SystemClock;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
@@ -24,6 +25,7 @@
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
 import android.view.View;
+import android.widget.RemoteViews;
 
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -53,6 +55,10 @@
         public boolean legacy; // whether the notification has a legacy, dark background
         public int targetSdk;
         private long lastFullScreenIntentLaunchTime = NOT_LAUNCHED_YET;
+        public RemoteViews cachedContentView;
+        public RemoteViews cachedBigContentView;
+        public RemoteViews cachedHeadsUpContentView;
+        public RemoteViews cachedPublicContentView;
 
         public Entry(StatusBarNotification n, StatusBarIconView ic) {
             this.key = n.getKey();
@@ -98,6 +104,67 @@
             return row.getPublicLayout().getContractedChild();
         }
 
+        public boolean cacheContentViews(Context ctx, Notification updatedNotification) {
+            boolean cached = false;
+            if (updatedNotification != null) {
+                final Notification.Builder updatedNotificationBuilder
+                        = Notification.Builder.recoverBuilder(ctx, updatedNotification);
+                final RemoteViews newContentView = updatedNotificationBuilder.makeContentView();
+                if (!compareRemoteViews(cachedContentView, newContentView)) {
+                    cachedContentView = newContentView;
+                    cached |= true;
+                }
+                final RemoteViews newBigContentView =
+                        updatedNotificationBuilder.makeBigContentView();
+                if (!compareRemoteViews(cachedBigContentView, newBigContentView)) {
+                    cachedBigContentView = newBigContentView;
+                    cached |= true;
+                }
+                final RemoteViews newHeadsUpContentView =
+                        updatedNotificationBuilder.makeHeadsUpContentView();
+                if (!compareRemoteViews(cachedHeadsUpContentView, newBigContentView)) {
+                    cachedHeadsUpContentView = newHeadsUpContentView;
+                    cached |= true;
+                }
+                final Notification updatedPublicNotification = updatedNotification.publicVersion;
+                final RemoteViews newPubContentView = (updatedPublicNotification != null)
+                        ? Notification.Builder.recoverBuilder(
+                                ctx, updatedPublicNotification).makeContentView()
+                        : null;
+                if (!compareRemoteViews(cachedPublicContentView, newPubContentView)) {
+                    cachedPublicContentView = newPubContentView;
+                    cached |= true;
+                }
+            } else {
+                final Notification.Builder builder
+                        = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
+
+                cachedContentView = builder.makeContentView();
+                cachedBigContentView = builder.makeBigContentView();
+                cachedHeadsUpContentView = builder.makeHeadsUpContentView();
+
+                final Notification publicNotification =
+                        notification.getNotification().publicVersion;
+                if (publicNotification != null) {
+                    final Notification.Builder publicBuilder
+                            = Notification.Builder.recoverBuilder(ctx, publicNotification);
+                    cachedPublicContentView = publicBuilder.makeContentView();
+                }
+                cached = true;
+            }
+            return cached;
+        }
+
+        // Returns true if the RemoteViews are the same.
+        private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+            return (a == null && b == null) ||
+                    (a != null && b != null
+                    && b.getPackage() != null
+                    && a.getPackage() != null
+                    && a.getPackage().equals(b.getPackage())
+                    && a.getLayoutId() == b.getLayoutId());
+        }
+
         public void notifyFullScreenIntentLaunched() {
             lastFullScreenIntentLaunchTime = SystemClock.elapsedRealtime();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 9653b67..8e8ce1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -70,13 +70,4 @@
     public NotificationOverflowIconsView getIconsView() {
         return mIconsView;
     }
-
-    protected int getContentHeightFromActualHeight(int actualHeight) {
-        int realActualHeight = actualHeight;
-        if (hasBottomDecor()) {
-            realActualHeight -= getBottomDecorHeight();
-        }
-        realActualHeight = Math.max(getMinHeight(), realActualHeight);
-        return realActualHeight;
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
index 958b8b5..af6ccd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationTemplateViewWrapper.java
@@ -27,10 +27,12 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
 import android.view.View;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
@@ -55,6 +57,11 @@
 
     /** Whether the icon needs to be forced grayscale when in dark mode. */
     private boolean mIconForceGraysaleWhenDark;
+    private TextView mSubText;
+    private TextView mInfoText;
+    private View mProfileBadge;
+    private View mThirdLineDivider;
+    private View mThirdLine;
 
     protected NotificationTemplateViewWrapper(Context ctx, View view) {
         super(view);
@@ -76,6 +83,11 @@
         mIcon = resolveIcon(largeIcon, rightIcon);
         mPicture = resolvePicture(largeIcon);
         mIconBackgroundColor = resolveBackgroundColor(mIcon);
+        mSubText = (TextView) mView.findViewById(com.android.internal.R.id.text);
+        mInfoText = (TextView) mView.findViewById(com.android.internal.R.id.info);
+        mProfileBadge = mView.findViewById(com.android.internal.R.id.profile_badge_line3);
+        mThirdLineDivider = mView.findViewById(com.android.internal.R.id.overflow_divider);
+        mThirdLine = mView.findViewById(com.android.internal.R.id.line3);
 
         // If the icon already has a color filter, we assume that we already forced the icon to be
         // white when we created the notification.
@@ -230,6 +242,43 @@
         }
     }
 
+    @Override
+    public void setSubTextVisible(boolean visible) {
+        if (mSubText == null) {
+            return;
+        }
+        boolean subTextAvailable = !TextUtils.isEmpty(mSubText.getText());
+        if (visible && subTextAvailable) {
+            mSubText.setVisibility(View.VISIBLE);
+        } else {
+            mSubText.setVisibility(View.GONE);
+        }
+        // TODO: figure out what to do with the number (same place as contentInfo)
+        // work profile badge. For now we hide it since it looks nicer.
+        boolean infoAvailable = !TextUtils.isEmpty(mInfoText.getText());
+        if (visible && infoAvailable) {
+            mInfoText.setVisibility(View.VISIBLE);
+        } else {
+            mInfoText.setVisibility(View.GONE);
+        }
+        boolean showThirdLine = (visible && (infoAvailable || subTextAvailable))
+                || mProfileBadge.getVisibility() == View.VISIBLE;
+        if (mThirdLineDivider != null) {
+            if (showThirdLine) {
+                mThirdLineDivider.setVisibility(View.VISIBLE);
+            } else {
+                mThirdLineDivider.setVisibility(View.GONE);
+            }
+        }
+        if (mThirdLine != null) {
+            if (showThirdLine) {
+                mThirdLine.setVisibility(View.VISIBLE);
+            } else {
+                mThirdLine.setVisibility(View.GONE);
+            }
+        }
+    }
+
     private void updateGrayscaleMatrix(float intensity) {
         mGrayscaleColorMatrix.setSaturation(1 - intensity);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
index b362a29..9bce548 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewWrapper.java
@@ -30,6 +30,7 @@
     private static final String TAG_BIG_PICTURE = "bigPicture";
 
     protected final View mView;
+    private boolean mSubTextVisible = true;
 
     public static NotificationViewWrapper wrap(Context ctx, View v) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
@@ -63,7 +64,9 @@
     /**
      * Notifies this wrapper that the content of the view might have changed.
      */
-    public void notifyContentUpdated() {}
+    public void notifyContentUpdated() {
+        setSubTextVisible(mSubTextVisible);
+    }
 
     /**
      * @return true if this template might need to be clipped with a round rect to make it look
@@ -72,4 +75,12 @@
     public boolean needsRoundRectClipping() {
         return false;
     }
+
+    /**
+     * Change the subTextVisibility
+     * @param visible Should the subtext be visible
+     */
+    public void setSubTextVisible(boolean visible) {
+        mSubTextVisible = visible;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
new file mode 100644
index 0000000..8f46e89
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationView.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.AlphaOptimizedFrameLayout;
+
+/**
+ * A hybrid view which may contain information about one ore more notifications.
+ */
+public class HybridNotificationView extends AlphaOptimizedFrameLayout {
+
+    protected final int mSingleLineHeight;
+    protected final int mStartMargin;
+    protected final int mEndMargin;
+    protected TextView mTitleView;
+    protected TextView mTextView;
+
+    public HybridNotificationView(Context context) {
+        this(context, null);
+    }
+
+    public HybridNotificationView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public HybridNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public HybridNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mSingleLineHeight = context.getResources().getDimensionPixelSize(
+                R.dimen.notification_single_line_height);
+        mStartMargin = context.getResources().getDimensionPixelSize(
+                R.dimen.notification_content_margin_start);
+        mEndMargin = context.getResources().getDimensionPixelSize(
+                R.dimen.notification_content_margin_end);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int totalWidth = MeasureSpec.getSize(widthMeasureSpec);
+        int remainingWidth = totalWidth - mStartMargin - mEndMargin;
+        int newHeightSpec = MeasureSpec.makeMeasureSpec(
+                MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST);
+        int newWidthSpec = MeasureSpec.makeMeasureSpec(remainingWidth, MeasureSpec.AT_MOST);
+        mTitleView.measure(newWidthSpec, newHeightSpec);
+        int maxTitleLength = getResources().getDimensionPixelSize(
+                R.dimen.notification_maximum_title_length);
+        int titleWidth = mTitleView.getMeasuredWidth();
+        int heightSpec = MeasureSpec.makeMeasureSpec(mSingleLineHeight, MeasureSpec.AT_MOST);
+        boolean hasText = !TextUtils.isEmpty(mTextView.getText());
+        if (titleWidth > maxTitleLength && hasText) {
+            titleWidth = maxTitleLength;
+            int widthSpec = MeasureSpec.makeMeasureSpec(titleWidth, MeasureSpec.EXACTLY);
+            mTitleView.measure(widthSpec, heightSpec);
+        }
+        if (hasText) {
+            remainingWidth -= titleWidth;
+            int widthSpec = MeasureSpec.makeMeasureSpec(remainingWidth, MeasureSpec.AT_MOST);
+            mTextView.measure(widthSpec, newHeightSpec);
+        }
+        setMeasuredDimension(totalWidth, mSingleLineHeight);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        int childLeft = mStartMargin;
+        int childRight = childLeft + mTitleView.getMeasuredWidth();
+        int childBottom = (mSingleLineHeight + mTitleView.getMeasuredHeight()) / 2;
+        int childTop = childBottom - mTitleView.getMeasuredHeight();
+        int rtlLeft = transformForRtl(childLeft);
+        int rtlRight = transformForRtl(childRight);
+        mTitleView.layout(Math.min(rtlLeft, rtlRight), childTop, Math.max(rtlLeft, rtlRight),
+                childBottom);
+        childLeft = childRight;
+        childRight = childLeft + mTextView.getMeasuredWidth();
+        childTop = mTitleView.getTop() + mTitleView.getBaseline() - mTextView.getBaseline();
+        childBottom = childTop + mTextView.getMeasuredHeight();
+        rtlLeft = transformForRtl(childLeft);
+        rtlRight = transformForRtl(childRight);
+        mTextView.layout(Math.min(rtlLeft, rtlRight), childTop, Math.max(rtlLeft, rtlRight),
+                childBottom);
+    }
+
+    private int transformForRtl(int left) {
+        return isLayoutRtl() ? getWidth() - left : left;
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mTitleView = (TextView) findViewById(R.id.notification_title);
+        mTextView = (TextView) findViewById(R.id.notification_text);
+    }
+
+    public void bind(CharSequence title) {
+        bind(title, null);
+    }
+
+    public void bind(CharSequence title, CharSequence text) {
+        mTitleView.setText(title);
+        mTextView.setText(text);
+        requestLayout();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
new file mode 100644
index 0000000..987f7b8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HybridNotificationViewManager.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.app.Notification;
+import android.content.Context;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
+import java.util.List;
+
+/**
+ * A class managing {@link HybridNotificationView} views
+ */
+public class HybridNotificationViewManager {
+
+    private final Context mContext;
+    private ViewGroup mParent;
+    private String mConcadenationString;
+
+    public HybridNotificationViewManager(Context ctx, ViewGroup parent) {
+        mContext = ctx;
+        mParent = parent;
+        mConcadenationString = mContext.getString(R.string.group_summary_concadenation);
+    }
+
+    private HybridNotificationView inflateHybridView() {
+        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
+        HybridNotificationView hybrid = (HybridNotificationView) inflater.inflate(
+                R.layout.hybrid_notification, mParent, false);
+        mParent.addView(hybrid);
+        return hybrid;
+    }
+
+    public HybridNotificationView bindFromNotification(HybridNotificationView reusableView,
+            Notification notification) {
+        CharSequence titleText = resolveTitle(notification);
+        if (titleText == null) {
+            if (reusableView != null) {
+                mParent.removeView(reusableView);
+            }
+            return null;
+        }
+        if (reusableView == null) {
+            reusableView = inflateHybridView();
+        }
+        CharSequence contentText = resolveText(notification);
+        reusableView.bind(titleText, contentText);
+        return reusableView;
+    }
+
+    private CharSequence resolveText(Notification notification) {
+        CharSequence contentText = notification.extras.getCharSequence(Notification.EXTRA_BIG_TEXT);
+        if (contentText == null) {
+            contentText = notification.extras.getCharSequence(Notification.EXTRA_TEXT);
+        }
+        return contentText;
+    }
+
+    private CharSequence resolveTitle(Notification notification) {
+        CharSequence titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE);
+        if (titleText == null) {
+            titleText = notification.extras.getCharSequence(Notification.EXTRA_TITLE_BIG);
+        }
+        return titleText;
+    }
+
+    public HybridNotificationView bindFromNotificationGroup(
+            HybridNotificationView reusableView,
+            List<ExpandableNotificationRow> group, int startIndex) {
+        if (reusableView == null) {
+            reusableView = inflateHybridView();
+        }
+        CharSequence summary = null;
+        int childCount = group.size();
+        for (int i = startIndex; i < childCount; i++) {
+            ExpandableNotificationRow child = group.get(i);
+            CharSequence titleText = resolveTitle(
+                    child.getStatusBarNotification().getNotification());
+            if (titleText == null) {
+                continue;
+            }
+            if (TextUtils.isEmpty(summary)) {
+                summary = titleText;
+            } else if (reusableView.isLayoutRtl()) {
+                summary = titleText + mConcadenationString + summary;
+            } else {
+                summary = summary + mConcadenationString + titleText;
+            }
+        }
+        reusableView.bind(summary);
+        return reusableView;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java
new file mode 100644
index 0000000..ec26cc4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderView.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.annotation.Nullable;
+import android.app.Notification;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.service.notification.StatusBarNotification;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
+
+import java.util.List;
+
+/**
+ * A header for a notification view
+ */
+public class NotificationHeaderView extends FrameLayout {
+
+    private static final int DEFAULT_ICON_TINT_COLOR = 0xff616161;
+    private final NotificationColorUtil mNotificationColorUtil;
+    private NotificationData.Entry mNotificationEntry;
+    private ImageView mIconView;
+    private TextView mAppName;
+    private TextView mPostTime;
+    private TextView mChildCount;
+    private TextView mSubTextDivider;
+    private TextView mSubText;
+    private NotificationGroupManager mGroupManager;
+    private ImageButton mExpandButton;
+
+    public NotificationHeaderView(Context context) {
+        this(context, null);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public NotificationHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mNotificationColorUtil = NotificationColorUtil.getInstance(context);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mIconView = (ImageView) findViewById(R.id.header_notification_icon);
+        mAppName = (TextView) findViewById(R.id.app_name_text);
+        mSubTextDivider = (TextView) findViewById(R.id.app_title_sub_text_divider);
+        mSubText = (TextView) findViewById(R.id.title_sub_text);
+        mPostTime = (TextView) findViewById(R.id.post_time);
+        mChildCount = (TextView) findViewById(R.id.number_of_children);
+        mExpandButton = (ImageButton) findViewById(R.id.notification_expand_button);
+        mExpandButton.setOnClickListener(new OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mGroupManager.toggleGroupExpansion(mNotificationEntry.notification);
+            }
+        });
+    }
+
+    public void bind(NotificationData.Entry notificationEntry) {
+        mNotificationEntry = notificationEntry;
+        StatusBarNotification sbn = notificationEntry.notification;
+        int notificationColor = getNotificationColor(sbn);
+        bindIcon(notificationColor);
+        bindNumber(notificationColor);
+        bindAppName(sbn);
+        bindSubText();
+        bindTime(sbn);
+        bindExpandButton(sbn);
+    }
+
+    private void bindExpandButton(StatusBarNotification sbn) {
+        boolean summaryOfGroup = mGroupManager.isSummaryOfGroup(sbn);
+        mExpandButton.setVisibility(summaryOfGroup ? VISIBLE : GONE);
+    }
+
+    private void bindSubText() {
+        List<ExpandableNotificationRow> notificationChildren =
+                mNotificationEntry.row.getNotificationChildren();
+        CharSequence subText = null;
+        if (notificationChildren != null) {
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow row = notificationChildren.get(i);
+                CharSequence rowSubText = row.getSubText();
+                if (TextUtils.isEmpty(rowSubText)
+                        || (subText != null && !subText.equals(rowSubText))) {
+                    // The children don't have a common subText
+                    subText = null;
+                    break;
+                } else if (subText == null) {
+                    subText = rowSubText;
+                }
+            }
+        };
+        setSubText(subText);
+    }
+
+    private void setSubText(CharSequence subText) {
+        boolean goneInHeader = TextUtils.isEmpty(subText);
+        if (goneInHeader) {
+            mSubText.setVisibility(GONE);
+            mSubTextDivider.setVisibility(GONE);
+        } else {
+            mSubText.setVisibility(VISIBLE);
+            mSubText.setText(subText);
+            mSubTextDivider.setVisibility(VISIBLE);
+        }
+        List<ExpandableNotificationRow> notificationChildren =
+                mNotificationEntry.row.getNotificationChildren();
+        if (notificationChildren != null) {
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow row = notificationChildren.get(i);
+                row.setContentSubTextVisible(goneInHeader);
+            }
+        }
+    }
+
+    private int getNotificationColor(StatusBarNotification sbn) {
+        int color = sbn.getNotification().color;
+        if (color == Notification.COLOR_DEFAULT) {
+            return DEFAULT_ICON_TINT_COLOR;
+        }
+        return color;
+    }
+
+    private void bindNumber(int notificationColor) {
+        int numberOfNotificationChildren = mNotificationEntry.row.getNumberOfNotificationChildren();
+        boolean visible = numberOfNotificationChildren > 0;
+        if (visible) {
+            mChildCount.setText("(" + numberOfNotificationChildren + ")");
+            mChildCount.setTextColor(notificationColor);
+            mChildCount.setVisibility(VISIBLE);
+        } else {
+            mChildCount.setVisibility(GONE);
+        }
+    }
+
+    private void bindTime(StatusBarNotification sbn) {
+
+    }
+
+    private void bindIcon(int notificationColor) {
+        Drawable icon = mNotificationEntry.icon.getDrawable().getConstantState()
+                .newDrawable(getResources()).mutate();
+        mIconView.setImageDrawable(icon);
+        if (NotificationUtils.isGrayscale(mIconView, mNotificationColorUtil)) {
+            icon.setTint(notificationColor);
+        }
+    }
+
+    private void bindAppName(StatusBarNotification sbn) {
+        PackageManager pmUser = BaseStatusBar.getPackageManagerForUser(getContext(),
+                sbn.getUser().getIdentifier());
+        final String pkg = sbn.getPackageName();
+        String appname = pkg;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                    PackageManager.GET_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            // app is gone, just show package name
+        }
+        mAppName.setText(appname);
+    }
+
+    public void setGroupManager(NotificationGroupManager groupManager) {
+        mGroupManager = groupManager;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
new file mode 100644
index 0000000..c931800
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import android.view.View;
+import android.widget.ImageView;
+
+import com.android.internal.util.NotificationColorUtil;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.StatusBarIconView;
+
+/**
+ * A util class for various reusable functions
+ */
+public class NotificationUtils {
+    public static boolean isGrayscale(ImageView v, NotificationColorUtil colorUtil) {
+        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
+        if (isGrayscale != null) {
+            return Boolean.TRUE.equals(isGrayscale);
+        }
+        boolean grayscale = colorUtil.isGrayscaleIcon(v.getDrawable());
+        v.setTag(R.id.icon_is_grayscale, grayscale);
+        return grayscale;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 310625e..bbef1c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -21,7 +21,6 @@
 
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
-import com.android.systemui.statusbar.StatusBarState;
 
 import java.util.HashMap;
 import java.util.HashSet;
@@ -93,21 +92,8 @@
         if (group.children.isEmpty()) {
             if (group.summary == null) {
                 mGroupMap.remove(groupKey);
-            } else {
-                if (group.expanded) {
-                    // only the summary is left. Change it to unexpanded in a few ms. We do this to
-                    // avoid raceconditions
-                    removed.row.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            if (group.children.isEmpty()) {
-                                setGroupExpanded(sbn, false);
-                            }
-                        }
-                    });
-                } else {
-                    group.summary.row.updateExpandButton();
-                }
+            } else if (!group.expanded) {
+                group.summary.row.updateNotificationHeader();
             }
         }
     }
@@ -130,7 +116,7 @@
         } else {
             group.children.add(added);
             if (group.summary != null && group.children.size() == 1 && !group.expanded) {
-                group.summary.row.updateExpandButton();
+                group.summary.row.updateNotificationHeader();
             }
         }
     }
@@ -155,9 +141,6 @@
     }
 
     public boolean hasGroupChildren(StatusBarNotification sbn) {
-        if (areGroupsProhibited()) {
-            return false;
-        }
         if (!sbn.getNotification().isGroupSummary()) {
             return false;
         }
@@ -168,29 +151,6 @@
         return !group.children.isEmpty();
     }
 
-    public void setStatusBarState(int newState) {
-        if (mBarState == newState) {
-            return;
-        }
-        boolean prohibitedBefore = areGroupsProhibited();
-        mBarState = newState;
-        boolean nowProhibited = areGroupsProhibited();
-        if (nowProhibited != prohibitedBefore) {
-            if (nowProhibited) {
-                for (NotificationGroup group : mGroupMap.values()) {
-                    if (group.expanded) {
-                        setGroupExpanded(group, false);
-                    }
-                }
-            }
-            mListener.onGroupsProhibitedChanged();
-        }
-    }
-
-    private boolean areGroupsProhibited() {
-        return mBarState == StatusBarState.KEYGUARD;
-    }
-
     /**
      * @return whether a given notification is a child in a group which has a summary
      */
@@ -205,6 +165,20 @@
         return true;
     }
 
+    /**
+     * @return whether a given notification is a summary in a group which has children
+     */
+    public boolean isSummaryOfGroup(StatusBarNotification sbn) {
+        if (sbn.getNotification().isGroupChild()) {
+            return false;
+        }
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null) {
+            return false;
+        }
+        return !group.children.isEmpty();
+    }
+
     public ExpandableNotificationRow getGroupSummary(StatusBarNotification sbn) {
         NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
         return group == null ? null
@@ -212,6 +186,18 @@
                 : group.summary.row;
     }
 
+    public void onEntryHeadsUped(NotificationData.Entry headsUp) {
+        // TODO: handle this nicely
+    }
+
+    public void toggleGroupExpansion(StatusBarNotification sbn) {
+        NotificationGroup group = mGroupMap.get(sbn.getGroupKey());
+        if (group == null) {
+            return;
+        }
+        setGroupExpanded(group, !group.expanded);
+    }
+
     public static class NotificationGroup {
         public final HashSet<NotificationData.Entry> children = new HashSet<>();
         public NotificationData.Entry summary;
@@ -228,11 +214,6 @@
         void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded);
 
         /**
-         * Children group policy has changed and children may no be prohibited or allowed.
-         */
-        void onGroupsProhibitedChanged();
-
-        /**
          * A group of children just received a summary notification and should therefore become
          * children of it.
          *
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 cfde791..3e52515 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -33,6 +33,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.database.ContentObserver;
@@ -88,7 +89,6 @@
 import android.view.ViewStub;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -146,7 +146,6 @@
 import com.android.systemui.statusbar.policy.FullscreenUserSwitcher;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
@@ -248,15 +247,25 @@
      * Prudently disable QS and notifications.  */
     private static final boolean ONLY_CORE_APPS;
 
+    /* If true, the device supports freeform window management.
+     * This affects the status bar UI. */
+    private static final boolean FREEFORM_WINDOW_MANAGEMENT;
+
     static {
         boolean onlyCoreApps;
+        boolean freeformWindowManagement;
         try {
-            onlyCoreApps = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
-                    .isOnlyCoreApps();
+            IPackageManager packageManager =
+                    IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+            onlyCoreApps = packageManager.isOnlyCoreApps();
+            freeformWindowManagement = packageManager.hasSystemFeature(
+                    PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
         } catch (RemoteException e) {
             onlyCoreApps = false;
+            freeformWindowManagement = false;
         }
         ONLY_CORE_APPS = onlyCoreApps;
+        FREEFORM_WINDOW_MANAGEMENT = freeformWindowManagement;
     }
 
     PhoneStatusBarPolicy mIconPolicy;
@@ -705,7 +714,7 @@
                     R.color.notification_panel_solid_background)));
         }
 
-        mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
+        mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
         mHeadsUpManager.setBar(this);
         mHeadsUpManager.addListener(this);
         mHeadsUpManager.addListener(mNotificationPanel);
@@ -984,8 +993,8 @@
         if (shelfOverride != DEFAULT) {
             return shelfOverride != 0;
         }
-        // Otherwise default to the build setting.
-        return mContext.getResources().getBoolean(R.bool.config_enableAppShelf);
+        // Otherwise default to the platform feature.
+        return FREEFORM_WINDOW_MANAGEMENT;
     }
 
     private void clearAllNotifications() {
@@ -1115,13 +1124,22 @@
         }
     };
 
-    private long mLastLockToAppLongPress;
-    private View.OnLongClickListener mLongPressBackRecentsListener =
-            new View.OnLongClickListener() {
+    private View.OnLongClickListener mLongPressBackListener = new View.OnLongClickListener() {
         @Override
         public boolean onLongClick(View v) {
-            handleLongPressBackRecents(v);
-            return true;
+            return handleLongPressBack();
+        }
+    };
+
+    private View.OnLongClickListener mRecentsLongClickListener = new View.OnLongClickListener() {
+
+        @Override
+        public boolean onLongClick(View v) {
+            if (mRecents != null) {
+                mRecents.dockTopTask();
+                return true;
+            }
+            return false;
         }
     };
 
@@ -1170,9 +1188,9 @@
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
         mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
         mNavigationBarView.getRecentsButton().setLongClickable(true);
-        mNavigationBarView.getRecentsButton().setOnLongClickListener(mLongPressBackRecentsListener);
+        mNavigationBarView.getRecentsButton().setOnLongClickListener(mRecentsLongClickListener);
         mNavigationBarView.getBackButton().setLongClickable(true);
-        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackRecentsListener);
+        mNavigationBarView.getBackButton().setOnLongClickListener(mLongPressBackListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeActionListener);
         mNavigationBarView.getHomeButton().setOnLongClickListener(mLongPressHomeListener);
         mAssistManager.onConfigurationChanged();
@@ -3841,7 +3859,6 @@
             clearNotificationEffects();
         }
         mState = state;
-        mGroupManager.setStatusBarState(state);
         mFalsingManager.setStatusBarState(state);
         mStatusBarWindowManager.setStatusBarState(state);
         updateDozing();
@@ -3968,9 +3985,6 @@
             mNotificationPanel.animateToFullShade(0 /* delay */);
             setBarState(StatusBarState.SHADE_LOCKED);
             updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
-            if (row != null) {
-                row.setUserLocked(false);
-            }
         }
     }
 
@@ -4048,7 +4062,7 @@
 
     private void vibrateForCameraGesture() {
         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
-        mVibrator.vibrate(new long[] { 0, 750L }, -1 /* repeat */);
+        mVibrator.vibrate(new long[]{0, 750L}, -1 /* repeat */);
     }
 
     public void onScreenTurnedOn() {
@@ -4057,58 +4071,22 @@
     }
 
     /**
-     * This handles long-press of both back and recents.  They are
-     * handled together to capture them both being long-pressed
-     * at the same time to exit screen pinning (lock task).
-     *
-     * When accessibility mode is on, only a long-press from recents
-     * is required to exit.
-     *
-     * In all other circumstances we try to pass through long-press events
-     * for Back, so that apps can still use it.  Which can be from two things.
-     * 1) Not currently in screen pinning (lock task).
-     * 2) Back is long-pressed without recents.
+     * Handles long press for back button. This exits screen pinning.
      */
-    private void handleLongPressBackRecents(View v) {
+    private boolean handleLongPressBack() {
         try {
-            boolean sendBackLongPress = false;
             IActivityManager activityManager = ActivityManagerNative.getDefault();
-            boolean isAccessiblityEnabled = mAccessibilityManager.isEnabled();
-            if (activityManager.isInLockTaskMode() && !isAccessiblityEnabled) {
-                long time = System.currentTimeMillis();
-                // If we recently long-pressed the other button then they were
-                // long-pressed 'together'
-                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
-                    activityManager.stopLockTaskModeOnCurrent();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                } else if ((v.getId() == R.id.back)
-                        && !mNavigationBarView.getRecentsButton().isPressed()) {
-                    // If we aren't pressing recents right now then they presses
-                    // won't be together, so send the standard long-press action.
-                    sendBackLongPress = true;
-                }
-                mLastLockToAppLongPress = time;
-            } else {
-                // If this is back still need to handle sending the long-press event.
-                if (v.getId() == R.id.back) {
-                    sendBackLongPress = true;
-                } else if (isAccessiblityEnabled && activityManager.isInLockTaskMode()) {
-                    // When in accessibility mode a long press that is recents (not back)
-                    // should stop lock task.
-                    activityManager.stopLockTaskModeOnCurrent();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                }
-            }
-            if (sendBackLongPress) {
-                KeyButtonView keyButtonView = (KeyButtonView) v;
-                keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
-                keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+            if (activityManager.isInLockTaskMode()) {
+                activityManager.stopLockTaskModeOnCurrent();
+
+                // When exiting refresh disabled flags.
+                mNavigationBarView.setDisabledFlags(mDisabled1, true);
+                return true;
             }
         } catch (RemoteException e) {
             Log.d(TAG, "Unable to reach activity manager", e);
         }
+        return false;
     }
 
     // Recents
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 5de1c13..d5b980e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -42,6 +42,7 @@
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -401,23 +402,13 @@
         for (int i = 0; i < mNotificationIcons.getChildCount(); i++) {
             StatusBarIconView v = (StatusBarIconView) mNotificationIcons.getChildAt(i);
             boolean isPreL = Boolean.TRUE.equals(v.getTag(R.id.icon_is_pre_L));
-            boolean colorize = !isPreL || isGrayscale(v);
+            boolean colorize = !isPreL || NotificationUtils.isGrayscale(v, mNotificationColorUtil);
             if (colorize) {
                 v.setImageTintList(ColorStateList.valueOf(mIconTint));
             }
         }
     }
 
-    private boolean isGrayscale(StatusBarIconView v) {
-        Object isGrayscale = v.getTag(R.id.icon_is_grayscale);
-        if (isGrayscale != null) {
-            return Boolean.TRUE.equals(isGrayscale);
-        }
-        boolean grayscale = mNotificationColorUtil.isGrayscaleIcon(v.getDrawable());
-        v.setTag(R.id.icon_is_grayscale, grayscale);
-        return grayscale;
-    }
-
     public void appTransitionPending() {
         mTransitionPending = true;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index a515f23..dc9f5e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -33,6 +33,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationData;
+import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.io.FileDescriptor;
@@ -85,6 +86,7 @@
     private final int mStatusBarHeight;
     private final int mNotificationsTopPadding;
     private final Context mContext;
+    private final NotificationGroupManager mGroupManager;
     private PhoneStatusBar mBar;
     private int mSnoozeLengthMs;
     private ContentObserver mSettingsObserver;
@@ -104,7 +106,8 @@
     private boolean mIsObserving;
     private boolean mRemoteInputActive;
 
-    public HeadsUpManager(final Context context, View statusBarWindowView) {
+    public HeadsUpManager(final Context context, View statusBarWindowView,
+                          NotificationGroupManager groupManager) {
         mContext = context;
         Resources resources = mContext.getResources();
         mTouchAcceptanceDelay = resources.getInteger(R.integer.touch_acceptance_delay);
@@ -132,6 +135,7 @@
                 Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
                 mSettingsObserver);
         mStatusBarWindowView = statusBarWindowView;
+        mGroupManager = groupManager;
         mStatusBarHeight = resources.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
         mNotificationsTopPadding = context.getResources()
@@ -181,12 +185,12 @@
     public void updateNotification(NotificationData.Entry headsUp, boolean alert) {
         if (DEBUG) Log.v(TAG, "updateNotification");
 
-        headsUp.row.setChildrenExpanded(false /* expanded */, false /* animated */);
         headsUp.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
 
         if (alert) {
             HeadsUpEntry headsUpEntry = mHeadsUpEntries.get(headsUp.key);
             headsUpEntry.updateEntry();
+            mGroupManager.onEntryHeadsUped(headsUp);
             setEntryPinned(headsUpEntry, shouldHeadsUpBecomePinned(headsUp));
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index 3c9e8cf..c9ebc84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -21,11 +21,11 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.Button;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
-import com.android.systemui.statusbar.ExpandableView;
+import com.android.systemui.statusbar.notification.HybridNotificationView;
+import com.android.systemui.statusbar.notification.HybridNotificationViewManager;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -35,15 +35,24 @@
  */
 public class NotificationChildrenContainer extends ViewGroup {
 
+    private static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2;
+    private static final int NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED = 5;
+    private static final int NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED = 8;
+
     private final int mChildPadding;
     private final int mDividerHeight;
     private final int mMaxNotificationHeight;
     private final List<View> mDividers = new ArrayList<>();
     private final List<ExpandableNotificationRow> mChildren = new ArrayList<>();
-    private final View mCollapseButton;
-    private final View mCollapseDivider;
-    private final int mCollapseButtonHeight;
+    private final int mNotificationHeaderHeight;
     private final int mNotificationAppearDistance;
+    private final float mHeaderTopPaddingSubstraction;
+    private final HybridNotificationViewManager mHybridViewManager;
+    private final float mCollapsedBottompadding;
+    private boolean mChildrenExpanded;
+    private ExpandableNotificationRow mNotificationParent;
+    private HybridNotificationView mGroupOverflowContainer;
+    private ViewState mGroupOverFlowState;
 
     public NotificationChildrenContainer(Context context) {
         this(context, null);
@@ -68,14 +77,11 @@
                 R.dimen.notification_max_height);
         mNotificationAppearDistance = getResources().getDimensionPixelSize(
                 R.dimen.notification_appear_distance);
-        LayoutInflater inflater = mContext.getSystemService(LayoutInflater.class);
-        mCollapseButton = inflater.inflate(R.layout.notification_collapse_button, this,
-                false);
-        mCollapseButtonHeight = getResources().getDimensionPixelSize(
-                R.dimen.notification_bottom_decor_height);
-        addView(mCollapseButton);
-        mCollapseDivider = inflateDivider();
-        addView(mCollapseDivider);
+        mNotificationHeaderHeight = getResources().getDimensionPixelSize(
+                R.dimen.notification_header_height);
+        mHeaderTopPaddingSubstraction = 2 * getResources().getDisplayMetrics().density;
+        mCollapsedBottompadding = 10 * getResources().getDisplayMetrics().density;
+        mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
     }
 
     @Override
@@ -85,14 +91,6 @@
         for (int i = 0; i < childCount; i++) {
             View child = mChildren.get(i);
             boolean viewGone = child.getVisibility() == View.GONE;
-            if (i != 0) {
-                View divider = mDividers.get(i - 1);
-                int dividerVisibility = divider.getVisibility();
-                int newVisibility = viewGone ? INVISIBLE : VISIBLE;
-                if (dividerVisibility != newVisibility) {
-                    divider.setVisibility(newVisibility);
-                }
-            }
             if (viewGone) {
                 continue;
             }
@@ -103,9 +101,10 @@
                 firstChild = false;
             }
         }
-        mCollapseButton.layout(0, 0, getWidth(), mCollapseButtonHeight);
-        mCollapseDivider.layout(0, mCollapseButtonHeight - mDividerHeight, getWidth(),
-                mCollapseButtonHeight);
+        if (mGroupOverflowContainer != null) {
+            mGroupOverflowContainer.layout(0, 0, getWidth(),
+                    mGroupOverflowContainer.getMeasuredHeight());
+        }
     }
 
     @Override
@@ -120,18 +119,11 @@
         }
         int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST);
         int dividerHeightSpec = MeasureSpec.makeMeasureSpec(mDividerHeight, MeasureSpec.EXACTLY);
-        int collapseButtonHeightSpec = MeasureSpec.makeMeasureSpec(mCollapseButtonHeight,
-                MeasureSpec.EXACTLY);
-        mCollapseButton.measure(widthMeasureSpec, collapseButtonHeightSpec);
-        mCollapseDivider.measure(widthMeasureSpec, dividerHeightSpec);
-        int height = mCollapseButtonHeight;
+        int height = mNotificationHeaderHeight;
         int childCount = mChildren.size();
         boolean firstChild = true;
         for (int i = 0; i < childCount; i++) {
             View child = mChildren.get(i);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
             child.measure(widthMeasureSpec, newHeightSpec);
             height += child.getMeasuredHeight();
             if (!firstChild) {
@@ -144,9 +136,9 @@
             }
         }
         int width = MeasureSpec.getSize(widthMeasureSpec);
-        height = hasFixedHeight ? ownMaxHeight
-                : isHeightLimited ? Math.min(ownMaxHeight, height)
-                : height;
+        if (mGroupOverflowContainer != null) {
+            mGroupOverflowContainer.measure(widthMeasureSpec, newHeightSpec);
+        }
         setMeasuredDimension(width, height);
     }
 
@@ -165,8 +157,7 @@
             addView(divider);
             mDividers.add(Math.max(newIndex - 1, 0), divider);
         }
-        // TODO: adapt background corners
-        // TODO: fix overdraw
+        updateGroupOverflow();
     }
 
     public void removeNotification(ExpandableNotificationRow row) {
@@ -178,7 +169,26 @@
             removeView(divider);
         }
         row.setSystemChildExpanded(false);
-        // TODO: adapt background corners
+        updateGroupOverflow();
+    }
+
+    public void updateGroupOverflow() {
+        int childCount = mChildren.size();
+        int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren(true /* likeCollapsed */);
+        boolean hasOverflow = childCount > maxAllowedVisibleChildren;
+        int lastVisibleIndex = hasOverflow ? maxAllowedVisibleChildren - 2
+                : maxAllowedVisibleChildren - 1;
+        if (hasOverflow) {
+            mGroupOverflowContainer = mHybridViewManager.bindFromNotificationGroup(
+                    mGroupOverflowContainer, mChildren, lastVisibleIndex + 1);
+            if (mGroupOverFlowState == null) {
+                mGroupOverFlowState = new ViewState();
+            }
+        } else if (mGroupOverflowContainer != null) {
+            removeView(mGroupOverflowContainer);
+            mGroupOverflowContainer = null;
+            mGroupOverFlowState = null;
+        }
     }
 
     private View inflateDivider() {
@@ -210,25 +220,42 @@
                 result = true;
             }
         }
-
-        // Let's make the first child expanded!
-        boolean first = true;
-        for (int i = 0; i < childOrder.size(); i++) {
-            ExpandableNotificationRow child = childOrder.get(i);
-            child.setSystemChildExpanded(first);
-            first = false;
-        }
+        updateExpansionStates();
         return result;
     }
 
+    private void updateExpansionStates() {
+        // Let's make the first child expanded if the parent is
+        for (int i = 0; i < mChildren.size(); i++) {
+            ExpandableNotificationRow child = mChildren.get(i);
+            child.setSystemChildExpanded(false);
+        }
+    }
+
+    /**
+     *
+     * @return the intrinsic size of this children container, i.e the natural fully expanded state
+     */
     public int getIntrinsicHeight() {
-        int childCount = mChildren.size();
+        int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
+        return getIntrinsicHeight(maxAllowedVisibleChildren);
+    }
+
+    /**
+     * @return the intrinsic height with a number of children given
+     *         in @param maxAllowedVisibleChildren
+     */
+    private int getIntrinsicHeight(float maxAllowedVisibleChildren) {
         int intrinsicHeight = 0;
         int visibleChildren = 0;
+        int childCount = mChildren.size();
         for (int i = 0; i < childCount; i++) {
+            if (visibleChildren >= maxAllowedVisibleChildren) {
+                break;
+            }
             ExpandableNotificationRow child = mChildren.get(i);
-            if (child.getVisibility() == View.GONE) {
-                continue;
+            if (i == 0 && child.hasSameBgColor(mNotificationParent)) {
+                intrinsicHeight -= mHeaderTopPaddingSubstraction;
             }
             intrinsicHeight += child.getIntrinsicHeight();
             visibleChildren++;
@@ -236,6 +263,9 @@
         if (visibleChildren > 0) {
             intrinsicHeight += (visibleChildren - 1) * mDividerHeight;
         }
+        if (!mChildrenExpanded) {
+            intrinsicHeight += mCollapsedBottompadding;
+        }
         return intrinsicHeight;
     }
 
@@ -247,17 +277,23 @@
      */
     public void getState(StackScrollState resultState, StackViewState parentState) {
         int childCount = mChildren.size();
-        int yPosition = mCollapseButtonHeight;
+        int yPosition = mNotificationHeaderHeight;
         boolean firstChild = true;
+        int maxAllowedVisibleChildren = getMaxAllowedVisibleChildren();
+        boolean hasOverflow = !mChildrenExpanded && childCount > maxAllowedVisibleChildren
+                && maxAllowedVisibleChildren != NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
+        int lastVisibleIndex = hasOverflow
+                ? maxAllowedVisibleChildren - 2
+                : maxAllowedVisibleChildren - 1;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
             if (!firstChild) {
                 // There's a divider
                 yPosition += mChildPadding;
             } else {
+                if (child.hasSameBgColor(mNotificationParent)) {
+                    yPosition -= mHeaderTopPaddingSubstraction;
+                }
                 firstChild = false;
             }
             StackViewState childState = resultState.getViewStateForView(child);
@@ -269,41 +305,62 @@
             childState.dark = parentState.dark;
             childState.hideSensitive = parentState.hideSensitive;
             childState.belowSpeedBump = parentState.belowSpeedBump;
-            childState.scale =  parentState.scale;
+            childState.scale =  1.0f;
             childState.clipTopAmount = 0;
             childState.topOverLap = 0;
+            boolean visible = i <= lastVisibleIndex;
+            childState.alpha = visible ? 1 : 0;
             childState.location = parentState.location;
             yPosition += intrinsicHeight;
         }
+        if (mGroupOverflowContainer != null) {
+            mGroupOverFlowState.initFrom(mGroupOverflowContainer);
+            if (hasOverflow) {
+                StackViewState firstOverflowState =
+                        resultState.getViewStateForView(mChildren.get(lastVisibleIndex + 1));
+                mGroupOverFlowState.yTranslation = firstOverflowState.yTranslation;
+            }
+            mGroupOverFlowState.alpha = mChildrenExpanded || !hasOverflow ? 0.0f : 1.0f;
+        }
+    }
+
+    private int getMaxAllowedVisibleChildren() {
+        return getMaxAllowedVisibleChildren(false /* likeCollapsed */);
+    }
+
+    private int getMaxAllowedVisibleChildren(boolean likeCollapsed) {
+        if (!likeCollapsed && (mChildrenExpanded || mNotificationParent.isUserLocked())) {
+            return NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED;
+        }
+        if (mNotificationParent.isExpanded()) {
+            return NUMBER_OF_CHILDREN_WHEN_SYSTEM_EXPANDED;
+        }
+        return NUMBER_OF_CHILDREN_WHEN_COLLAPSED;
     }
 
     public void applyState(StackScrollState state) {
         int childCount = mChildren.size();
         boolean firstChild = true;
-        ViewState dividerState = new ViewState();
+        ViewState tmpState = new ViewState();
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
             if (!firstChild) {
                 // layout the divider
                 View divider = mDividers.get(i - 1);
-                dividerState.initFrom(divider);
-                dividerState.yTranslation = (int) (viewState.yTranslation
+                tmpState.initFrom(divider);
+                tmpState.yTranslation = (int) (viewState.yTranslation
                         - (mChildPadding + mDividerHeight) / 2.0f);
-                dividerState.alpha = 1;
-                state.applyViewState(divider, dividerState);
+                tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;
+                state.applyViewState(divider, tmpState);
             } else {
                 firstChild = false;
             }
             state.applyState(child, viewState);
         }
-    }
-
-    public void setCollapseClickListener(OnClickListener collapseClickListener) {
-        mCollapseButton.setOnClickListener(collapseClickListener);
+        if (mGroupOverflowContainer != null) {
+            state.applyViewState(mGroupOverflowContainer, mGroupOverFlowState);
+        }
     }
 
     /**
@@ -313,6 +370,10 @@
      * @param state the new state we animate to
      */
     public void prepareExpansionChanged(StackScrollState state) {
+        if (true) {
+            // TODO: do something that makes sense
+            return;
+        }
         int childCount = mChildren.size();
         boolean firstChild = true;
         StackViewState sourceState = new StackViewState();
@@ -320,9 +381,6 @@
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
             if (!firstChild) {
                 // layout the divider
                 View divider = mDividers.get(i - 1);
@@ -339,23 +397,17 @@
             sourceState.yTranslation += mNotificationAppearDistance;
             state.applyState(child, sourceState);
         }
-        mCollapseButton.setAlpha(0);
-        mCollapseDivider.setAlpha(0);
-        mCollapseDivider.setTranslationY(mNotificationAppearDistance / 4);
     }
 
     public void startAnimationToState(StackScrollState state, StackStateAnimator stateAnimator,
             boolean withDelays, long baseDelay, long duration) {
         int childCount = mChildren.size();
         boolean firstChild = true;
-        ViewState dividerState = new ViewState();
+        ViewState tmpState = new ViewState();
         int notGoneIndex = 0;
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             StackViewState viewState = state.getViewStateForView(child);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
             int difference = Math.min(StackStateAnimator.DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN,
                     notGoneIndex + 1);
             long delay = withDelays
@@ -365,24 +417,20 @@
             if (!firstChild) {
                 // layout the divider
                 View divider = mDividers.get(i - 1);
-                dividerState.initFrom(divider);
-                dividerState.yTranslation = viewState.yTranslation
+                tmpState.initFrom(divider);
+                tmpState.yTranslation = viewState.yTranslation
                         - (mChildPadding + mDividerHeight) / 2.0f;
-                dividerState.alpha = 1;
-                stateAnimator.startViewAnimations(divider, dividerState, delay, duration);
+                tmpState.alpha = mChildrenExpanded && viewState.alpha != 0 ? 0.5f : 0;;
+                stateAnimator.startViewAnimations(divider, tmpState, delay, duration);
             } else {
                 firstChild = false;
             }
             stateAnimator.startStackAnimations(child, viewState, state, -1, delay);
             notGoneIndex++;
         }
-        dividerState.initFrom(mCollapseButton);
-        dividerState.alpha = 1.0f;
-        stateAnimator.startViewAnimations(mCollapseButton, dividerState, baseDelay, duration);
-        dividerState.initFrom(mCollapseDivider);
-        dividerState.alpha = 1.0f;
-        dividerState.yTranslation = 0.0f;
-        stateAnimator.startViewAnimations(mCollapseDivider, dividerState, baseDelay, duration);
+        if (mGroupOverflowContainer != null) {
+            stateAnimator.startViewAnimations(mGroupOverflowContainer, mGroupOverFlowState, -1, 0);
+        }
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
@@ -400,7 +448,19 @@
         return null;
     }
 
-    public void setTintColor(int color) {
-        ExpandableNotificationRow.applyTint(mCollapseDivider, color);
+    public void setChildrenExpanded(boolean childrenExpanded) {
+        mChildrenExpanded = childrenExpanded;
+    }
+
+    public void setNotificationParent(ExpandableNotificationRow parent) {
+        mNotificationParent = parent;
+    }
+
+    public int getMaxContentHeight() {
+        return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_CHILDREN_EXPANDED);
+    }
+
+    public int getMinHeight() {
+        return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index d50f8ac5..aeca97c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -747,7 +747,8 @@
 
     public void setUserExpandedChild(View v, boolean userExpanded) {
         if (v instanceof ExpandableNotificationRow) {
-            ((ExpandableNotificationRow) v).setUserExpanded(userExpanded);
+            ((ExpandableNotificationRow) v).setUserExpanded(userExpanded,
+                    true /* allowChildrenExpansion */);
         }
     }
 
@@ -1726,7 +1727,7 @@
             ExpandableNotificationRow groupSummary =
                     mGroupManager.getGroupSummary(row.getStatusBarNotification());
             if (groupSummary != null && groupSummary != row) {
-                return !groupSummary.areChildrenExpanded();
+                return row.getVisibility() == View.INVISIBLE;
             }
         }
         return false;
@@ -2344,7 +2345,13 @@
             ExpandableNotificationRow row = (ExpandableNotificationRow) view;
             if (row.isUserLocked() && row != getFirstChildNotGone()) {
                 // We are actually expanding this view
-                float endPosition = row.getTranslationY() + row.getActualHeight();
+                float endPosition;
+                if (row.isChildInGroup()) {
+                    ExpandableNotificationRow parent = row.getNotificationParent();
+                    endPosition = parent.getTranslationY() + parent.getActualHeight();
+                } else {
+                    endPosition = row.getTranslationY() + row.getActualHeight();
+                }
                 int stackEnd = mMaxLayoutHeight - mBottomStackPeekSize -
                         mBottomStackSlowDownHeight + (int) mStackTranslation;
                 if (endPosition > stackEnd) {
@@ -2788,16 +2795,6 @@
         return touchY > mTopPadding + mStackTranslation;
     }
 
-    private void updateExpandButtons() {
-        for (int i = 0; i < getChildCount(); i++) {
-            View child = getChildAt(i);
-            if (child instanceof ExpandableNotificationRow) {
-                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                row.updateExpandButton();
-            }
-        }
-    }
-
     @Override
     public void onGroupExpansionChanged(ExpandableNotificationRow changedRow, boolean expanded) {
         boolean animated = mAnimationsEnabled && mIsExpanded;
@@ -2810,11 +2807,6 @@
     }
 
     @Override
-    public void onGroupsProhibitedChanged() {
-        updateExpandButtons();
-    }
-
-    @Override
     public void onGroupCreatedFromChildren(NotificationGroupManager.NotificationGroup group) {
         for (NotificationData.Entry entry : group.children) {
             ExpandableNotificationRow row = entry.row;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index cf696a1..65ca95b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -361,7 +361,7 @@
                     // handle the notgoneIndex for the children as well
                     List<ExpandableNotificationRow> children =
                             row.getNotificationChildren();
-                    if (row.areChildrenExpanded() && children != null) {
+                    if (row.isSummaryWithChildren() && children != null) {
                         for (ExpandableNotificationRow childRow : children) {
                             if (childRow.getVisibility() != View.GONE) {
                                 StackViewState childState
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 3768ca4..e155d70 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -65,7 +65,7 @@
                 ExpandableNotificationRow row = (ExpandableNotificationRow) child;
                 List<ExpandableNotificationRow> children =
                         row.getNotificationChildren();
-                if (row.areChildrenExpanded() && children != null) {
+                if (row.isSummaryWithChildren() && children != null) {
                     for (ExpandableNotificationRow childRow : children) {
                         resetViewState(childRow);
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 4ce0933..05e3fd5 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -46,6 +46,7 @@
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.QSTile.ResourceIcon;
+import com.android.systemui.qs.QSTileBaseView;
 import com.android.systemui.qs.QSTileView;
 import com.android.systemui.qs.tiles.IntentTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
@@ -381,7 +382,7 @@
     private static class DraggableTile extends QSTile<QSTile.State>
             implements DropListener {
         private String mSpec;
-        private QSTileView mView;
+        private QSTileBaseView mView;
 
         protected DraggableTile(QSTile.Host host, String tileSpec) {
             super(host);
@@ -390,7 +391,7 @@
         }
 
         @Override
-        public QSTileView createTileView(Context context) {
+        public QSTileBaseView createTileView(Context context) {
             mView = super.createTileView(context);
             return mView;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
index 1cf7a70f..673a30b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java
@@ -125,10 +125,6 @@
         return mAudio;
     }
 
-    public ZenModeConfig getZenModeConfig() {
-        return mNoMan.getZenModeConfig();
-    }
-
     public void dismiss() {
         mCallbacks.onDismissRequested(Events.DISMISS_REASON_VOLUME_CONTROLLER);
     }
@@ -348,7 +344,6 @@
         updateRingerModeExternalW(mAudio.getRingerMode());
         updateZenModeW();
         updateEffectsSuppressorW(mNoMan.getEffectsSuppressor());
-        updateZenModeConfigW();
         mCallbacks.onStateChanged(mState);
     }
 
@@ -401,13 +396,6 @@
         return stream == AudioManager.STREAM_RING || stream == AudioManager.STREAM_NOTIFICATION;
     }
 
-    private boolean updateZenModeConfigW() {
-        final ZenModeConfig zenModeConfig = getZenModeConfig();
-        if (Objects.equals(mState.zenModeConfig, zenModeConfig)) return false;
-        mState.zenModeConfig = zenModeConfig;
-        return true;
-    }
-
     private boolean updateEffectsSuppressorW(ComponentName effectsSuppressor) {
         if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false;
         mState.effectsSuppressor = effectsSuppressor;
@@ -748,9 +736,6 @@
             if (ZEN_MODE_URI.equals(uri)) {
                 changed = updateZenModeW();
             }
-            if (ZEN_MODE_CONFIG_URI.equals(uri)) {
-                changed = updateZenModeConfigW();
-            }
             if (changed) {
                 mCallbacks.onStateChanged(mState);
             }
@@ -947,7 +932,6 @@
         public int zenMode;
         public ComponentName effectsSuppressor;
         public String effectsSuppressorName;
-        public ZenModeConfig zenModeConfig;
         public int activeStream = NO_ACTIVE_STREAM;
 
         public State copy() {
@@ -960,7 +944,6 @@
             rt.zenMode = zenMode;
             if (effectsSuppressor != null) rt.effectsSuppressor = effectsSuppressor.clone();
             rt.effectsSuppressorName = effectsSuppressorName;
-            if (zenModeConfig != null) rt.zenModeConfig = zenModeConfig.copy();
             rt.activeStream = activeStream;
             return rt;
         }
@@ -989,7 +972,6 @@
             sep(sb, indent); sb.append("zenMode:").append(zenMode);
             sep(sb, indent); sb.append("effectsSuppressor:").append(effectsSuppressor);
             sep(sb, indent); sb.append("effectsSuppressorName:").append(effectsSuppressorName);
-            sep(sb, indent); sb.append("zenModeConfig:").append(zenModeConfig);
             sep(sb, indent); sb.append("activeStream:").append(activeStream);
             if (indent > 0) sep(sb, indent);
             return sb.append('}').toString();
@@ -1005,11 +987,6 @@
                 sb.append(',');
             }
         }
-
-        public Condition getManualExitCondition() {
-            return zenModeConfig != null && zenModeConfig.manualRule != null
-                    ? zenModeConfig.manualRule.condition : null;
-        }
     }
 
     public interface Callbacks {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index f156607..a03e7f7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -141,6 +141,7 @@
     public void onConfigurationChanged() {
         mEndNowButton.setText(mContext.getString(R.string.volume_zen_end_now));
         mSpTexts.update();
+        Util.setText(mEndNowButton, mContext.getString(R.string.volume_zen_end_now));
     }
 
 }
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 3759c91..be7071e 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -64,6 +64,10 @@
     case RS_TYPE_FLOAT_32:                                                              \
         len = _env->GetArrayLength((jfloatArray)data);                                  \
         ptr = _env->GetFloatArrayElements((jfloatArray)data, flag);                     \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 4;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -89,6 +93,10 @@
     case RS_TYPE_FLOAT_64:                                                              \
         len = _env->GetArrayLength((jdoubleArray)data);                                 \
         ptr = _env->GetDoubleArrayElements((jdoubleArray)data, flag);                   \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 8;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -115,6 +123,10 @@
     case RS_TYPE_UNSIGNED_8:                                                            \
         len = _env->GetArrayLength((jbyteArray)data);                                   \
         ptr = _env->GetByteArrayElements((jbyteArray)data, flag);                       \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 1;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -141,6 +153,10 @@
     case RS_TYPE_UNSIGNED_16:                                                           \
         len = _env->GetArrayLength((jshortArray)data);                                  \
         ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 2;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -167,6 +183,10 @@
     case RS_TYPE_UNSIGNED_32:                                                           \
         len = _env->GetArrayLength((jintArray)data);                                    \
         ptr = _env->GetIntArrayElements((jintArray)data, flag);                         \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 4;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -193,6 +213,10 @@
     case RS_TYPE_UNSIGNED_64:                                                           \
         len = _env->GetArrayLength((jlongArray)data);                                   \
         ptr = _env->GetLongArrayElements((jlongArray)data, flag);                       \
+        if (ptr == nullptr) {                                                           \
+            ALOGE("Failed to get Java array elements.");                                \
+            return;                                                                     \
+        }                                                                               \
         typeBytes = 8;                                                                  \
         if (usePadding) {                                                               \
             srcPtr = ptr;                                                               \
@@ -332,16 +356,40 @@
 
   jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
   jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
+  if (jFieldIDs == nullptr) {
+      ALOGE("Failed to get Java array elements: fieldIDs.");
+      return ret;
+  }
+
   jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
   jsize values_length = _env->GetArrayLength(valueArray);
+  if (jValues == nullptr) {
+      ALOGE("Failed to get Java array elements: values.");
+      return ret;
+  }
+
   jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
   jsize sizes_length = _env->GetArrayLength(sizeArray);
+  if (jSizes == nullptr) {
+      ALOGE("Failed to get Java array elements: sizes.");
+      return ret;
+  }
+
   jlong* jDepClosures =
       _env->GetLongArrayElements(depClosureArray, nullptr);
   jsize depClosures_length = _env->GetArrayLength(depClosureArray);
+  if (jDepClosures == nullptr) {
+      ALOGE("Failed to get Java array elements: depClosures.");
+      return ret;
+  }
+
   jlong* jDepFieldIDs =
       _env->GetLongArrayElements(depFieldIDArray, nullptr);
   jsize depFieldIDs_length = _env->GetArrayLength(depFieldIDArray);
+  if (jDepFieldIDs == nullptr) {
+      ALOGE("Failed to get Java array elements: depFieldIDs.");
+      return ret;
+  }
 
   size_t numValues, numDependencies;
   RsScriptFieldID* fieldIDs;
@@ -435,12 +483,31 @@
 
   jbyte* jParams = _env->GetByteArrayElements(paramArray, nullptr);
   jsize jParamLength = _env->GetArrayLength(paramArray);
+  if (jParams == nullptr) {
+      ALOGE("Failed to get Java array elements: params.");
+      return ret;
+  }
+
   jlong* jFieldIDs = _env->GetLongArrayElements(fieldIDArray, nullptr);
   jsize fieldIDs_length = _env->GetArrayLength(fieldIDArray);
+  if (jFieldIDs == nullptr) {
+      ALOGE("Failed to get Java array elements: fieldIDs.");
+      return ret;
+  }
+
   jlong* jValues = _env->GetLongArrayElements(valueArray, nullptr);
   jsize values_length = _env->GetArrayLength(valueArray);
+  if (jValues == nullptr) {
+      ALOGE("Failed to get Java array elements: values.");
+      return ret;
+  }
+
   jint* jSizes = _env->GetIntArrayElements(sizeArray, nullptr);
   jsize sizes_length = _env->GetArrayLength(sizeArray);
+  if (jSizes == nullptr) {
+      ALOGE("Failed to get Java array elements: sizes.");
+      return ret;
+  }
 
   size_t numValues;
   RsScriptFieldID* fieldIDs;
@@ -515,6 +582,10 @@
 
   jlong* jClosures = _env->GetLongArrayElements(closureArray, nullptr);
   jsize numClosures = _env->GetArrayLength(closureArray);
+  if (jClosures == nullptr) {
+      ALOGE("Failed to get Java array elements: closures.");
+      return ret;
+  }
 
   RsClosure* closures;
 
@@ -720,6 +791,11 @@
     }
     jint len = _env->GetArrayLength(str);
     jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0);
+    if (cptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
+
     rsAssignName((RsContext)con, (void *)obj, (const char *)cptr, len);
     _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT);
 }
@@ -916,6 +992,10 @@
         ALOGD("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
     }
     jint *ptr = _env->GetIntArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return 0;
+    }
     size_t receiveLen;
     uint32_t subID;
     int id = rsContextGetMessage((RsContext)con,
@@ -936,6 +1016,10 @@
         ALOGD("nContextPeekMessage, con(%p)", (RsContext)con);
     }
     jint *auxDataPtr = _env->GetIntArrayElements(auxData, nullptr);
+    if (auxDataPtr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return 0;
+    }
     size_t receiveLen;
     uint32_t subID;
     int id = rsContextPeekMessage((RsContext)con, &receiveLen, sizeof(receiveLen),
@@ -970,6 +1054,10 @@
     if (data) {
         len = _env->GetArrayLength(data);
         ptr = _env->GetIntArrayElements(data, nullptr);
+        if (ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            return;
+        }
     }
     if (kLogApi) {
         ALOGD("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
@@ -1004,7 +1092,15 @@
     }
 
     jlong *jIds = _env->GetLongArrayElements(_ids, nullptr);
+    if (jIds == nullptr) {
+        ALOGE("Failed to get Java array elements: ids");
+        return 0;
+    }
     jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, nullptr);
+    if (jArraySizes == nullptr) {
+        ALOGE("Failed to get Java array elements: arraySizes");
+        return 0;
+    }
 
     RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
     uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
@@ -1311,6 +1407,10 @@
               sizeBytes);
     }
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsAllocationElementData((RsContext)con, (RsAllocation)alloc,
                             xoff, yoff, zoff,
                             lod, ptr, sizeBytes, compIdx);
@@ -1449,6 +1549,10 @@
               sizeBytes);
     }
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsAllocationElementRead((RsContext)con, (RsAllocation)alloc,
                             xoff, yoff, zoff,
                             lod, ptr, sizeBytes, compIdx);
@@ -1775,6 +1879,10 @@
     }
     jint len = _env->GetArrayLength(data);
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
@@ -1787,6 +1895,10 @@
     }
     jint len = _env->GetArrayLength(data);
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsScriptGetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, 0);
 }
@@ -1800,8 +1912,16 @@
     }
     jint len = _env->GetArrayLength(data);
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     jint dimsLen = _env->GetArrayLength(dims) * sizeof(int);
     jint *dimsPtr = _env->GetIntArrayElements(dims, nullptr);
+    if (dimsPtr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
                      (const uint32_t*) dimsPtr, dimsLen);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
@@ -1819,6 +1939,10 @@
     jint length = _env->GetArrayLength(timeZone);
     jbyte* timeZone_ptr;
     timeZone_ptr = (jbyte *) _env->GetPrimitiveArrayCritical(timeZone, (jboolean *)0);
+    if (timeZone_ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
 
     rsScriptSetTimeZone((RsContext)con, (RsScript)script, (const char *)timeZone_ptr, length);
 
@@ -1844,6 +1968,10 @@
     }
     jint len = _env->GetArrayLength(data);
     jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
+    if (ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return;
+    }
     rsScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
     _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
 }
@@ -1870,8 +1998,12 @@
             return;
         }
 
-        // TODO (b/20760800): Check in_ptr is not null
         in_ptr = _env->GetLongArrayElements(ains, nullptr);
+        if (in_ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            return;
+        }
+
         if (sizeof(RsAllocation) == sizeof(jlong)) {
             in_allocs = (RsAllocation*)in_ptr;
 
@@ -1897,6 +2029,10 @@
     if (params != nullptr) {
         param_len = _env->GetArrayLength(params);
         param_ptr = _env->GetByteArrayElements(params, nullptr);
+        if (param_ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            return;
+        }
     }
 
     RsScriptCall sc, *sca = nullptr;
@@ -1908,6 +2044,10 @@
     if (limits != nullptr) {
         limit_len = _env->GetArrayLength(limits);
         limit_ptr = _env->GetIntArrayElements(limits, nullptr);
+        if (limit_ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            return;
+        }
 
         assert(limit_len == 6);
         UNUSED(limit_len);  // As the assert might not be compiled.
@@ -1966,6 +2106,10 @@
     if (limits != nullptr) {
         limit_len = _env->GetArrayLength(limits);
         limit_ptr = _env->GetIntArrayElements(limits, nullptr);
+        if (limit_ptr == nullptr) {
+            ALOGE("Failed to get Java array elements");
+            return;
+        }
 
         // We expect to be passed an array [x1, x2] which specifies
         // the sub-range for a 1-dimensional reduction.
@@ -2037,6 +2181,10 @@
     }
     script_ptr = (jbyte *)
         _env->GetPrimitiveArrayCritical(scriptRef, (jboolean *)0);
+    if (script_ptr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return ret;
+    }
 
     //rsScriptCSetText((RsContext)con, (const char *)script_ptr, length);
 
@@ -2104,6 +2252,10 @@
 
     jint kernelsLen = _env->GetArrayLength(_kernels);
     jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
+    if (jKernelsPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: kernels");
+        return 0;
+    }
     RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
     for(int i = 0; i < kernelsLen; ++i) {
         kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
@@ -2111,6 +2263,10 @@
 
     jint srcLen = _env->GetArrayLength(_src);
     jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
+    if (jSrcPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: src");
+        return 0;
+    }
     RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
     for(int i = 0; i < srcLen; ++i) {
         srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
@@ -2118,6 +2274,10 @@
 
     jint dstkLen = _env->GetArrayLength(_dstk);
     jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
+    if (jDstkPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: dstk");
+        return 0;
+    }
     RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
     for(int i = 0; i < dstkLen; ++i) {
         dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
@@ -2125,6 +2285,10 @@
 
     jint dstfLen = _env->GetArrayLength(_dstf);
     jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
+    if (jDstfPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: dstf");
+        return 0;
+    }
     RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
     for(int i = 0; i < dstfLen; ++i) {
         dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
@@ -2132,6 +2296,10 @@
 
     jint typesLen = _env->GetArrayLength(_types);
     jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
+    if (jTypesPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: types");
+        return 0;
+    }
     RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
     for(int i = 0; i < typesLen; ++i) {
         typesPtr[i] = (RsType)jTypesPtr[i];
@@ -2244,6 +2412,10 @@
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
     jint paramLen = _env->GetArrayLength(params);
+    if (jParamPtr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return 0;
+    }
 
     int texCount = _env->GetArrayLength(texNames);
     AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
@@ -2277,6 +2449,10 @@
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
     jint paramLen = _env->GetArrayLength(params);
+    if (jParamPtr == nullptr) {
+        ALOGE("Failed to get Java array elements");
+        return 0;
+    }
 
     if (kLogApi) {
         ALOGD("nProgramVertexCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
@@ -2392,6 +2568,10 @@
 
     jint vtxLen = _env->GetArrayLength(_vtx);
     jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, nullptr);
+    if (jVtxPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: vtx");
+        return 0;
+    }
     RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
     for(int i = 0; i < vtxLen; ++i) {
         vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
@@ -2399,6 +2579,10 @@
 
     jint idxLen = _env->GetArrayLength(_idx);
     jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
+    if (jIdxPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: idx");
+        return 0;
+    }
     RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
     for(int i = 0; i < idxLen; ++i) {
         idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
@@ -2406,6 +2590,10 @@
 
     jint primLen = _env->GetArrayLength(_prim);
     jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
+    if (primPtr == nullptr) {
+        ALOGE("Failed to get Java array elements: prim");
+        return 0;
+    }
 
     jlong id = (jlong)(uintptr_t)rsMeshCreate((RsContext)con,
                                (RsAllocation *)vtxPtr, vtxLen,
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 08f0952..a5ddc12 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -20,7 +20,10 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
+import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
+import android.app.IAlarmCompleteListener;
+import android.app.IAlarmListener;
 import android.app.IAlarmManager;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
@@ -94,11 +97,13 @@
     static final boolean DEBUG_BATCH = localLOGV || false;
     static final boolean DEBUG_VALIDATE = localLOGV || false;
     static final boolean DEBUG_ALARM_CLOCK = localLOGV || false;
+    static final boolean DEBUG_LISTENER_CALLBACK = localLOGV || false;
     static final boolean RECORD_ALARMS_IN_HISTORY = true;
+    static final boolean RECORD_DEVICE_IDLE_ALARMS = false;
     static final int ALARM_EVENT = 1;
     static final String TIMEZONE_PROPERTY = "persist.sys.timezone";
 
-    static final Intent mBackgroundIntent
+    private final Intent mBackgroundIntent
             = new Intent().addFlags(Intent.FLAG_FROM_BACKGROUND);
     static final IncreasingTimeOrder sIncreasingTimeOrder = new IncreasingTimeOrder();
     
@@ -109,6 +114,8 @@
 
     final LocalLog mLog = new LocalLog(TAG);
 
+    AppOpsManager mAppOps;
+
     final Object mLock = new Object();
 
     long mNativeData;
@@ -123,7 +130,7 @@
     ClockReceiver mClockReceiver;
     InteractiveStateReceiver mInteractiveStateReceiver;
     private UninstallReceiver mUninstallReceiver;
-    final ResultReceiver mResultReceiver = new ResultReceiver();
+    final DeliveryTracker mDeliveryTracker = new DeliveryTracker();
     PendingIntent mTimeTickSender;
     PendingIntent mDateChangeSender;
     Random mRandom;
@@ -144,6 +151,16 @@
      */
     final SparseLongArray mLastAllowWhileIdleDispatch = new SparseLongArray();
 
+    final static class IdleDispatchEntry {
+        int uid;
+        String pkg;
+        String tag;
+        String op;
+        long elapsedRealtime;
+        long argRealtime;
+    }
+    final ArrayList<IdleDispatchEntry> mAllowWhileIdleDispatches = new ArrayList();
+
     /**
      * Broadcast options to use for FLAG_ALLOW_WHILE_IDLE.
      */
@@ -174,13 +191,16 @@
         private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time";
         private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION
                 = "allow_while_idle_whitelist_duration";
+        private static final String KEY_LISTENER_TIMEOUT = "listener_timeout";
 
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
-        private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
+        private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
 
+        private static final long DEFAULT_LISTENER_TIMEOUT = 5 * 1000;
+
         // Minimum futurity of a new alarm
         public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
 
@@ -197,6 +217,9 @@
         public long ALLOW_WHILE_IDLE_WHITELIST_DURATION
                 = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION;
 
+        // Direct alarm listener callback timeout
+        public long LISTENER_TIMEOUT = DEFAULT_LISTENER_TIMEOUT;
+
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
         private long mLastAllowWhileIdleWhitelistDuration = -1;
@@ -253,6 +276,8 @@
                 ALLOW_WHILE_IDLE_WHITELIST_DURATION = mParser.getLong(
                         KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION,
                         DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION);
+                LISTENER_TIMEOUT = mParser.getLong(KEY_LISTENER_TIMEOUT,
+                        DEFAULT_LISTENER_TIMEOUT);
 
                 updateAllowWhileIdleMinTimeLocked();
                 updateAllowWhileIdleWhitelistDurationLocked();
@@ -270,6 +295,10 @@
             TimeUtils.formatDuration(MIN_INTERVAL, pw);
             pw.println();
 
+            pw.print("    "); pw.print(KEY_LISTENER_TIMEOUT); pw.print("=");
+            TimeUtils.formatDuration(LISTENER_TIMEOUT, pw);
+            pw.println();
+
             pw.print("    "); pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("=");
             TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw);
             pw.println();
@@ -377,14 +406,21 @@
             return newStart;
         }
 
-        boolean remove(final PendingIntent operation) {
+        boolean remove(final PendingIntent operation, final IAlarmListener listener) {
+            if (operation == null && listener == null) {
+                if (localLOGV) {
+                    Slog.w(TAG, "requested remove() of null operation",
+                            new RuntimeException("here"));
+                }
+                return false;
+            }
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
             int newFlags = 0;
             for (int i = 0; i < alarms.size(); ) {
                 Alarm alarm = alarms.get(i);
-                if (alarm.operation.equals(operation)) {
+                if (alarm.matches(operation, listener)) {
                     alarms.remove(i);
                     didRemove = true;
                     if (alarm.alarmClock != null) {
@@ -411,13 +447,20 @@
         }
 
         boolean remove(final String packageName) {
+            if (packageName == null) {
+                if (localLOGV) {
+                    Slog.w(TAG, "requested remove() of null packageName",
+                            new RuntimeException("here"));
+                }
+                return false;
+            }
             boolean didRemove = false;
             long newStart = 0;  // recalculate endpoints as we go
             long newEnd = Long.MAX_VALUE;
             int newFlags = 0;
             for (int i = 0; i < alarms.size(); ) {
                 Alarm alarm = alarms.get(i);
-                if (alarm.operation.getTargetPackage().equals(packageName)) {
+                if (alarm.matches(packageName)) {
                     alarms.remove(i);
                     didRemove = true;
                     if (alarm.alarmClock != null) {
@@ -449,7 +492,7 @@
             long newEnd = Long.MAX_VALUE;
             for (int i = 0; i < alarms.size(); ) {
                 Alarm alarm = alarms.get(i);
-                if (UserHandle.getUserId(alarm.operation.getCreatorUid()) == userHandle) {
+                if (UserHandle.getUserId(alarm.creatorUid) == userHandle) {
                     alarms.remove(i);
                     didRemove = true;
                     if (alarm.alarmClock != null) {
@@ -477,7 +520,7 @@
             final int N = alarms.size();
             for (int i = 0; i < N; i++) {
                 Alarm a = alarms.get(i);
-                if (a.operation.getTargetPackage().equals(packageName)) {
+                if (a.matches(packageName)) {
                     return true;
                 }
             }
@@ -554,7 +597,8 @@
             Alarm a = alarms.get(i);
 
             final int alarmPrio;
-            if (Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
+            if (a.operation != null
+                    && Intent.ACTION_TIME_TICK.equals(a.operation.getIntent().getAction())) {
                 alarmPrio = PRIO_TICK;
             } else if (a.wakeup) {
                 alarmPrio = PRIO_WAKEUP;
@@ -563,10 +607,13 @@
             }
 
             PriorityClass packagePrio = a.priorityClass;
-            if (packagePrio == null) packagePrio = mPriorities.get(a.operation.getCreatorPackage());
+            String alarmPackage = (a.operation != null)
+                    ? a.operation.getCreatorPackage()
+                    : a.packageName;
+            if (packagePrio == null) packagePrio = mPriorities.get(alarmPackage);
             if (packagePrio == null) {
                 packagePrio = a.priorityClass = new PriorityClass(); // lowest prio & stale sequence
-                mPriorities.put(a.operation.getCreatorPackage(), packagePrio);
+                mPriorities.put(alarmPackage, packagePrio);
             }
             a.priorityClass = packagePrio;
 
@@ -700,6 +747,14 @@
     }
 
     void restorePendingWhileIdleAlarmsLocked() {
+        if (RECORD_DEVICE_IDLE_ALARMS) {
+            IdleDispatchEntry ent = new IdleDispatchEntry();
+            ent.uid = 0;
+            ent.pkg = "FINISH IDLE";
+            ent.elapsedRealtime = SystemClock.elapsedRealtime();
+            mAllowWhileIdleDispatches.add(ent);
+        }
+
         // Bring pending alarms back into the main list.
         if (mPendingWhileIdleAlarms.size() > 0) {
             ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
@@ -725,20 +780,27 @@
         }
     }
 
-    static final class InFlight extends Intent {
+    static final class InFlight {
         final PendingIntent mPendingIntent;
+        final IBinder mListener;
         final WorkSource mWorkSource;
+        final int mUid;
         final String mTag;
         final BroadcastStats mBroadcastStats;
         final FilterStats mFilterStats;
         final int mAlarmType;
 
-        InFlight(AlarmManagerService service, PendingIntent pendingIntent, WorkSource workSource,
-                int alarmType, String tag, long nowELAPSED) {
+        InFlight(AlarmManagerService service, PendingIntent pendingIntent, IAlarmListener listener,
+                WorkSource workSource, int uid, String alarmPkg, int alarmType, String tag,
+                long nowELAPSED) {
             mPendingIntent = pendingIntent;
+            mListener = listener != null ? listener.asBinder() : null;
             mWorkSource = workSource;
+            mUid = uid;
             mTag = tag;
-            mBroadcastStats = service.getStatsLocked(pendingIntent);
+            mBroadcastStats = (pendingIntent != null)
+                    ? service.getStatsLocked(pendingIntent)
+                    : service.getStatsLocked(uid, alarmPkg);
             FilterStats fs = mBroadcastStats.filterStats.get(mTag);
             if (fs == null) {
                 fs = new FilterStats(mBroadcastStats, mTag);
@@ -834,6 +896,7 @@
     public void onBootPhase(int phase) {
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             mConstants.start(getContext().getContentResolver());
+            mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         }
     }
 
@@ -886,15 +949,20 @@
             return;
         }
         synchronized (mLock) {
-            removeLocked(operation);
+            removeLocked(operation, null);
         }
     }
 
     void setImpl(int type, long triggerAtTime, long windowLength, long interval,
-            PendingIntent operation, int flags, WorkSource workSource,
-            AlarmManager.AlarmClockInfo alarmClock, int callingUid) {
-        if (operation == null) {
-            Slog.w(TAG, "set/setRepeating ignored because there is no intent");
+            PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
+            int flags, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
+            int callingUid, String callingPackage) {
+        // must be *either* PendingIntent or AlarmReceiver, but not both
+        if ((operation == null && directReceiver == null)
+                || (operation != null && directReceiver != null)) {
+            Slog.w(TAG, "Alarms must either supply a PendingIntent or an AlarmReceiver");
+            // NB: previous releases failed silently here, so we are continuing to do the same
+            // rather than throw an IllegalArgumentException.
             return;
         }
 
@@ -952,17 +1020,19 @@
                         + " interval=" + interval + " flags=0x" + Integer.toHexString(flags));
             }
             setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
-                    interval, operation, flags, true, workSource, alarmClock, callingUid);
+                    interval, operation, directReceiver, listenerTag, flags, true, workSource,
+                    alarmClock, callingUid, callingPackage);
         }
     }
 
     private void setImplLocked(int type, long when, long whenElapsed, long windowLength,
-            long maxWhen, long interval, PendingIntent operation, int flags,
-            boolean doValidate, WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock,
-            int uid) {
+            long maxWhen, long interval, PendingIntent operation, IAlarmListener directReceiver,
+            String listenerTag, int flags, boolean doValidate, WorkSource workSource,
+            AlarmManager.AlarmClockInfo alarmClock, int callingUid, String callingPackage) {
         Alarm a = new Alarm(type, when, whenElapsed, windowLength, maxWhen, interval,
-                operation, workSource, flags, alarmClock, uid);
-        removeLocked(operation);
+                operation, directReceiver, listenerTag, workSource, flags, alarmClock,
+                callingUid, callingPackage);
+        removeLocked(operation, directReceiver);
         setImplLocked(a, false, doValidate);
     }
 
@@ -1006,6 +1076,19 @@
             }
         }
 
+        if (RECORD_DEVICE_IDLE_ALARMS) {
+            if ((a.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
+                IdleDispatchEntry ent = new IdleDispatchEntry();
+                ent.uid = a.uid;
+                ent.pkg = a.operation.getCreatorPackage();
+                ent.tag = a.operation.getTag("");
+                ent.op = "SET";
+                ent.elapsedRealtime = SystemClock.elapsedRealtime();
+                ent.argRealtime = a.whenElapsed;
+                mAllowWhileIdleDispatches.add(ent);
+            }
+        }
+
         int whichBatch = ((a.flags&AlarmManager.FLAG_STANDALONE) != 0)
                 ? -1 : attemptCoalesceLocked(a.whenElapsed, a.maxWhenElapsed);
         if (whichBatch < 0) {
@@ -1028,6 +1111,15 @@
         boolean needRebatch = false;
 
         if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) {
+            if (RECORD_DEVICE_IDLE_ALARMS) {
+                if (mPendingIdleUntil == null) {
+                    IdleDispatchEntry ent = new IdleDispatchEntry();
+                    ent.uid = 0;
+                    ent.pkg = "START IDLE";
+                    ent.elapsedRealtime = SystemClock.elapsedRealtime();
+                    mAllowWhileIdleDispatches.add(ent);
+                }
+            }
             mPendingIdleUntil = a;
             mConstants.updateAllowWhileIdleMinTimeLocked();
             needRebatch = true;
@@ -1068,10 +1160,31 @@
 
     private final IBinder mService = new IAlarmManager.Stub() {
         @Override
-        public void set(int type, long triggerAtTime, long windowLength, long interval, int flags,
-                PendingIntent operation, WorkSource workSource,
-                AlarmManager.AlarmClockInfo alarmClock) {
+        public void set(String callingPackage,
+                int type, long triggerAtTime, long windowLength, long interval, int flags,
+                PendingIntent operation, IAlarmListener directReceiver, String listenerTag,
+                WorkSource workSource, AlarmManager.AlarmClockInfo alarmClock) {
             final int callingUid = Binder.getCallingUid();
+
+            // make sure the caller is not lying about which package should be blamed for
+            // wakelock time spent in alarm delivery
+            mAppOps.checkPackage(callingUid, callingPackage);
+
+            // Repeating alarms must use PendingIntent, not direct listener
+            if (interval != 0) {
+                if (directReceiver != null) {
+                    throw new IllegalArgumentException("Repeating alarms cannot use AlarmReceivers");
+                }
+            }
+
+            // direct-callback alarms must be wakeup alarms (otherwise they should just be
+            // posting work to a Handler)
+            if (directReceiver != null) {
+                if (type != RTC_WAKEUP && type != ELAPSED_REALTIME_WAKEUP) {
+                    throw new IllegalArgumentException("Only wakeup alarms can use AlarmReceivers");
+                }
+            }
+
             if (workSource != null) {
                 getContext().enforcePermission(
                         android.Manifest.permission.UPDATE_DEVICE_STATS,
@@ -1108,8 +1221,8 @@
                 flags |= AlarmManager.FLAG_WAKE_FROM_IDLE | AlarmManager.FLAG_STANDALONE;
             }
 
-            setImpl(type, triggerAtTime, windowLength, interval, operation,
-                    flags, workSource, alarmClock, callingUid);
+            setImpl(type, triggerAtTime, windowLength, interval, operation, directReceiver,
+                    listenerTag, flags, workSource, alarmClock, callingUid, callingPackage);
         }
 
         @Override
@@ -1143,9 +1256,15 @@
         }
 
         @Override
-        public void remove(PendingIntent operation) {
-            removeImpl(operation);
+        public void remove(PendingIntent operation, IAlarmListener listener) {
+            if (operation == null && listener == null) {
+                Slog.w(TAG, "remove() with no intent or listener");
+                return;
+            }
 
+            synchronized (mLock) {
+                removeLocked(operation, listener);
+            }
         }
 
         @Override
@@ -1400,6 +1519,32 @@
                 }
             }
 
+            if (RECORD_DEVICE_IDLE_ALARMS) {
+                pw.println();
+                pw.println("  Allow while idle dispatches:");
+                for (int i = 0; i < mAllowWhileIdleDispatches.size(); i++) {
+                    IdleDispatchEntry ent = mAllowWhileIdleDispatches.get(i);
+                    pw.print("    ");
+                    TimeUtils.formatDuration(ent.elapsedRealtime, nowELAPSED, pw);
+                    pw.print(": ");
+                    UserHandle.formatUid(pw, ent.uid);
+                    pw.print(":");
+                    pw.println(ent.pkg);
+                    if (ent.op != null) {
+                        pw.print("      ");
+                        pw.print(ent.op);
+                        pw.print(" / ");
+                        pw.print(ent.tag);
+                        if (ent.argRealtime != 0) {
+                            pw.print(" (");
+                            TimeUtils.formatDuration(ent.argRealtime, nowELAPSED, pw);
+                            pw.print(")");
+                        }
+                        pw.println();
+                    }
+                }
+            }
+
             if (WAKEUP_STATS) {
                 pw.println();
                 pw.println("  Recent Wakeup History:");
@@ -1630,17 +1775,17 @@
         }
     }
 
-    private void removeLocked(PendingIntent operation) {
+    private void removeLocked(PendingIntent operation, IAlarmListener directReceiver) {
         boolean didRemove = false;
         for (int i = mAlarmBatches.size() - 1; i >= 0; i--) {
             Batch b = mAlarmBatches.get(i);
-            didRemove |= b.remove(operation);
+            didRemove |= b.remove(operation, directReceiver);
             if (b.size() == 0) {
                 mAlarmBatches.remove(i);
             }
         }
         for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
-            if (mPendingWhileIdleAlarms.get(i).operation.equals(operation)) {
+            if (mPendingWhileIdleAlarms.get(i).matches(operation, directReceiver)) {
                 // Don't set didRemove, since this doesn't impact the scheduled alarms.
                 mPendingWhileIdleAlarms.remove(i);
             }
@@ -1651,11 +1796,11 @@
                 Slog.v(TAG, "remove(operation) changed bounds; rebatching");
             }
             boolean restorePending = false;
-            if (mPendingIdleUntil != null && mPendingIdleUntil.operation.equals(operation)) {
+            if (mPendingIdleUntil != null && mPendingIdleUntil.matches(operation, directReceiver)) {
                 mPendingIdleUntil = null;
                 restorePending = true;
             }
-            if (mNextWakeFromIdle != null && mNextWakeFromIdle.operation.equals(operation)) {
+            if (mNextWakeFromIdle != null && mNextWakeFromIdle.matches(operation, directReceiver)) {
                 mNextWakeFromIdle = null;
             }
             rebatchAllAlarmsLocked(true);
@@ -1676,7 +1821,8 @@
             }
         }
         for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
-            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
+            final Alarm a = mPendingWhileIdleAlarms.get(i);
+            if (a.matches(packageName)) {
                 // Don't set didRemove, since this doesn't impact the scheduled alarms.
                 mPendingWhileIdleAlarms.remove(i);
             }
@@ -1702,7 +1848,7 @@
             }
         }
         for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
-            if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).operation.getCreatorUid())
+            if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).creatorUid)
                     == userHandle) {
                 // Don't set didRemove, since this doesn't impact the scheduled alarms.
                 mPendingWhileIdleAlarms.remove(i);
@@ -1758,7 +1904,8 @@
             }
         }
         for (int i = 0; i < mPendingWhileIdleAlarms.size(); i++) {
-            if (mPendingWhileIdleAlarms.get(i).operation.getTargetPackage().equals(packageName)) {
+            final Alarm a = mPendingWhileIdleAlarms.get(i);
+            if (a.matches(packageName)) {
                 return true;
             }
         }
@@ -1862,6 +2009,16 @@
                         if (alarm.maxWhenElapsed < minTime) {
                             alarm.maxWhenElapsed = minTime;
                         }
+                        if (RECORD_DEVICE_IDLE_ALARMS) {
+                            IdleDispatchEntry ent = new IdleDispatchEntry();
+                            ent.uid = alarm.uid;
+                            ent.pkg = alarm.operation.getCreatorPackage();
+                            ent.tag = alarm.operation.getTag("");
+                            ent.op = "RESCHEDULE";
+                            ent.elapsedRealtime = nowELAPSED;
+                            ent.argRealtime = lastTime;
+                            mAllowWhileIdleDispatches.add(ent);
+                        }
                         setImplLocked(alarm, true, false);
                         continue;
                     }
@@ -1871,7 +2028,7 @@
                 triggerList.add(alarm);
                 if ((alarm.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) {
                     EventLogTags.writeDeviceIdleWakeFromIdle(mPendingIdleUntil != null ? 1 : 0,
-                            alarm.tag);
+                            alarm.statsTag);
                 }
                 if (mPendingIdleUntil == alarm) {
                     mPendingIdleUntil = null;
@@ -1895,8 +2052,8 @@
                     final long nextElapsed = alarm.whenElapsed + delta;
                     setImplLocked(alarm.type, alarm.when + delta, nextElapsed, alarm.windowLength,
                             maxTriggerTime(nowELAPSED, nextElapsed, alarm.repeatInterval),
-                            alarm.repeatInterval, alarm.operation, alarm.flags, true,
-                            alarm.workSource, alarm.alarmClock, alarm.uid);
+                            alarm.repeatInterval, alarm.operation, null, null, alarm.flags, true,
+                            alarm.workSource, alarm.alarmClock, alarm.uid, alarm.packageName);
                 }
 
                 if (alarm.wakeup) {
@@ -1947,11 +2104,15 @@
         public final long origWhen;
         public final boolean wakeup;
         public final PendingIntent operation;
-        public final String tag;
+        public final IAlarmListener listener;
+        public final String listenerTag;
+        public final String statsTag;
         public final WorkSource workSource;
         public final int flags;
         public final AlarmManager.AlarmClockInfo alarmClock;
         public final int uid;
+        public final int creatorUid;
+        public final String packageName;
         public int count;
         public long when;
         public long windowLength;
@@ -1961,8 +2122,9 @@
         public PriorityClass priorityClass;
 
         public Alarm(int _type, long _when, long _whenElapsed, long _windowLength, long _maxWhen,
-                long _interval, PendingIntent _op, WorkSource _ws, int _flags,
-                AlarmManager.AlarmClockInfo _info, int _uid) {
+                long _interval, PendingIntent _op, IAlarmListener _rec, String _listenerTag,
+                WorkSource _ws, int _flags, AlarmManager.AlarmClockInfo _info,
+                int _uid, String _pkgName) {
             type = _type;
             origWhen = _when;
             wakeup = _type == AlarmManager.ELAPSED_REALTIME_WAKEUP
@@ -1973,16 +2135,42 @@
             maxWhenElapsed = _maxWhen;
             repeatInterval = _interval;
             operation = _op;
-            tag = makeTag(_op, _type);
+            listener = _rec;
+            listenerTag = _listenerTag;
+            statsTag = makeTag(_op, _listenerTag, _type);
             workSource = _ws;
             flags = _flags;
             alarmClock = _info;
             uid = _uid;
+            packageName = _pkgName;
+
+            creatorUid = (operation != null) ? operation.getCreatorUid() : uid;
         }
 
-        public static String makeTag(PendingIntent pi, int type) {
-            return pi.getTag(type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
-                    ? "*walarm*:" : "*alarm*:");
+        public static String makeTag(PendingIntent pi, String tag, int type) {
+            final String alarmString = type == ELAPSED_REALTIME_WAKEUP || type == RTC_WAKEUP
+                    ? "*walarm*:" : "*alarm*:";
+            return (pi != null) ? pi.getTag(alarmString) : (alarmString + tag);
+        }
+
+        public WakeupEvent makeWakeupEvent(long nowRTC) {
+            return new WakeupEvent(nowRTC, creatorUid,
+                    (operation != null)
+                        ? operation.getIntent().getAction()
+                        : ("<listener>:" + listenerTag));
+        }
+
+        // Returns true if either matches
+        public boolean matches(PendingIntent pi, IAlarmListener rec) {
+            return (operation != null)
+                    ? operation.equals(pi)
+                    : listener.asBinder().equals(rec.asBinder());
+        }
+
+        public boolean matches(String packageName) {
+            return (operation != null)
+                    ? packageName.equals(operation.getTargetPackage())
+                    : packageName.equals(this.packageName);
         }
 
         @Override
@@ -1995,7 +2183,11 @@
             sb.append(" when ");
             sb.append(when);
             sb.append(" ");
-            sb.append(operation.getTargetPackage());
+            if (operation != null) {
+                sb.append(operation.getTargetPackage());
+            } else {
+                sb.append(listener.asBinder().toString());
+            }
             sb.append('}');
             return sb.toString();
         }
@@ -2003,14 +2195,15 @@
         public void dump(PrintWriter pw, String prefix, long nowRTC, long nowELAPSED,
                 SimpleDateFormat sdf) {
             final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
-            pw.print(prefix); pw.print("tag="); pw.println(tag);
+            pw.print(prefix); pw.print("tag="); pw.println(statsTag);
             pw.print(prefix); pw.print("type="); pw.print(type);
                     pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
                             nowELAPSED, pw);
+                    pw.print(" when=");
                     if (isRtc) {
-                        pw.print(" when="); pw.print(sdf.format(new Date(when)));
+                        pw.print(sdf.format(new Date(when)));
                     } else {
-                        pw.print(" when="); TimeUtils.formatDuration(when, nowELAPSED, pw);
+                        TimeUtils.formatDuration(when, nowELAPSED, pw);
                     }
                     pw.println();
             pw.print(prefix); pw.print("window="); TimeUtils.formatDuration(windowLength, pw);
@@ -2024,6 +2217,9 @@
                 pw.print(prefix); pw.print("  showIntent="); pw.println(alarmClock.getShowIntent());
             }
             pw.print(prefix); pw.print("operation="); pw.println(operation);
+            if (listener != null) {
+                pw.print(prefix); pw.print("listener="); pw.println(listener.asBinder());
+            }
         }
     }
 
@@ -2038,10 +2234,7 @@
             final int numAlarms = b.alarms.size();
             for (int nextAlarm = 0; nextAlarm < numAlarms; nextAlarm++) {
                 Alarm a = b.alarms.get(nextAlarm);
-                WakeupEvent e = new WakeupEvent(nowRTC,
-                        a.operation.getCreatorUid(),
-                        a.operation.getIntent().getAction());
-                mRecentWakeups.add(e);
+                mRecentWakeups.add(a.makeWakeupEvent(nowRTC));
             }
         }
     }
@@ -2104,71 +2297,14 @@
                     if (alarm.workSource != null && alarm.workSource.size() > 0) {
                         for (int wi=0; wi<alarm.workSource.size(); wi++) {
                             ActivityManagerNative.noteAlarmStart(
-                                    alarm.operation, alarm.workSource.get(wi), alarm.tag);
+                                    alarm.operation, alarm.workSource.get(wi), alarm.statsTag);
                         }
                     } else {
                         ActivityManagerNative.noteAlarmStart(
-                                alarm.operation, -1, alarm.tag);
+                                alarm.operation, alarm.uid, alarm.statsTag);
                     }
                 }
-                alarm.operation.send(getContext(), 0,
-                        mBackgroundIntent.putExtra(
-                                Intent.EXTRA_ALARM_COUNT, alarm.count),
-                        mResultReceiver, mHandler, null, allowWhileIdle ? mIdleOptions : null);
-
-                // we have an active broadcast so stay awake.
-                if (mBroadcastRefCount == 0) {
-                    setWakelockWorkSource(alarm.operation, alarm.workSource,
-                            alarm.type, alarm.tag, true);
-                    mWakeLock.acquire();
-                }
-                final InFlight inflight = new InFlight(AlarmManagerService.this,
-                        alarm.operation, alarm.workSource, alarm.type, alarm.tag, nowELAPSED);
-                mInFlight.add(inflight);
-                mBroadcastRefCount++;
-
-                if (allowWhileIdle) {
-                    // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
-                    mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED);
-                }
-
-                final BroadcastStats bs = inflight.mBroadcastStats;
-                bs.count++;
-                if (bs.nesting == 0) {
-                    bs.nesting = 1;
-                    bs.startTime = nowELAPSED;
-                } else {
-                    bs.nesting++;
-                }
-                final FilterStats fs = inflight.mFilterStats;
-                fs.count++;
-                if (fs.nesting == 0) {
-                    fs.nesting = 1;
-                    fs.startTime = nowELAPSED;
-                } else {
-                    fs.nesting++;
-                }
-                if (alarm.type == ELAPSED_REALTIME_WAKEUP
-                        || alarm.type == RTC_WAKEUP) {
-                    bs.numWakeup++;
-                    fs.numWakeup++;
-                    if (alarm.workSource != null && alarm.workSource.size() > 0) {
-                        for (int wi=0; wi<alarm.workSource.size(); wi++) {
-                            ActivityManagerNative.noteWakeupAlarm(
-                                    alarm.operation, alarm.workSource.get(wi),
-                                    alarm.workSource.getName(wi), alarm.tag);
-                        }
-                    } else {
-                        ActivityManagerNative.noteWakeupAlarm(
-                                alarm.operation, -1, null, alarm.tag);
-                    }
-                }
-            } catch (PendingIntent.CanceledException e) {
-                if (alarm.repeatInterval > 0) {
-                    // This IntentSender is no longer valid, but this
-                    // is a repeating alarm, so toss the hoser.
-                    removeImpl(alarm.operation);
-                }
+                mDeliveryTracker.deliverLocked(alarm, nowELAPSED, allowWhileIdle);
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Failure sending alarm.", e);
             }
@@ -2298,9 +2434,10 @@
      * Attribute blame for a WakeLock.
      * @param pi PendingIntent to attribute blame to if ws is null.
      * @param ws WorkSource to attribute blame.
+     * @param knownUid attribution uid; < 0 if we need to derive it from the PendingIntent sender
      */
     void setWakelockWorkSource(PendingIntent pi, WorkSource ws, int type, String tag,
-            boolean first) {
+            int knownUid, boolean first) {
         try {
             final boolean unimportant = pi == mTimeTickSender;
             mWakeLock.setUnimportantForLogging(unimportant);
@@ -2315,8 +2452,9 @@
                 return;
             }
 
-            final int uid = ActivityManagerNative.getDefault()
-                    .getUidForIntentSender(pi.getTarget());
+            final int uid = (knownUid >= 0)
+                    ? knownUid
+                    : ActivityManagerNative.getDefault().getUidForIntentSender(pi.getTarget());
             if (uid >= 0) {
                 mWakeLock.setWorkSource(new WorkSource(uid));
                 return;
@@ -2333,35 +2471,49 @@
         public static final int MINUTE_CHANGE_EVENT = 2;
         public static final int DATE_CHANGE_EVENT = 3;
         public static final int SEND_NEXT_ALARM_CLOCK_CHANGED = 4;
+        public static final int LISTENER_TIMEOUT = 5;
         
         public AlarmHandler() {
         }
         
         public void handleMessage(Message msg) {
-            if (msg.what == ALARM_EVENT) {
-                ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
-                synchronized (mLock) {
-                    final long nowRTC = System.currentTimeMillis();
-                    final long nowELAPSED = SystemClock.elapsedRealtime();
-                    triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
-                    updateNextAlarmClockLocked();
-                }
+            switch (msg.what) {
+                case ALARM_EVENT: {
+                    ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
+                    synchronized (mLock) {
+                        final long nowRTC = System.currentTimeMillis();
+                        final long nowELAPSED = SystemClock.elapsedRealtime();
+                        triggerAlarmsLocked(triggerList, nowELAPSED, nowRTC);
+                        updateNextAlarmClockLocked();
+                    }
 
-                // now trigger the alarms without the lock held
-                for (int i=0; i<triggerList.size(); i++) {
-                    Alarm alarm = triggerList.get(i);
-                    try {
-                        alarm.operation.send();
-                    } catch (PendingIntent.CanceledException e) {
-                        if (alarm.repeatInterval > 0) {
-                            // This IntentSender is no longer valid, but this
-                            // is a repeating alarm, so toss the hoser.
-                            removeImpl(alarm.operation);
+                    // now trigger the alarms without the lock held
+                    for (int i=0; i<triggerList.size(); i++) {
+                        Alarm alarm = triggerList.get(i);
+                        try {
+                            alarm.operation.send();
+                        } catch (PendingIntent.CanceledException e) {
+                            if (alarm.repeatInterval > 0) {
+                                // This IntentSender is no longer valid, but this
+                                // is a repeating alarm, so toss the hoser.
+                                removeImpl(alarm.operation);
+                            }
                         }
                     }
+                    break;
                 }
-            } else if (msg.what == SEND_NEXT_ALARM_CLOCK_CHANGED) {
-                sendNextAlarmClockChanged();
+
+                case SEND_NEXT_ALARM_CLOCK_CHANGED:
+                    sendNextAlarmClockChanged();
+                    break;
+
+                case LISTENER_TIMEOUT:
+                    mDeliveryTracker.alarmTimedOut((IBinder) msg.obj);
+                    break;
+
+                default:
+                    // nope, just ignore it
+                    break;
             }
         }
     }
@@ -2403,8 +2555,8 @@
 
             final WorkSource workSource = null; // Let system take blame for time tick events.
             setImpl(ELAPSED_REALTIME, SystemClock.elapsedRealtime() + tickEventDelay, 0,
-                    0, mTimeTickSender, AlarmManager.FLAG_STANDALONE, workSource, null,
-                    Process.myUid());
+                    0, mTimeTickSender, null, null, AlarmManager.FLAG_STANDALONE, workSource,
+                    null, Process.myUid(), "android");
         }
 
         public void scheduleDateChangedEvent() {
@@ -2417,8 +2569,9 @@
             calendar.add(Calendar.DAY_OF_MONTH, 1);
 
             final WorkSource workSource = null; // Let system take blame for date change events.
-            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender,
-                    AlarmManager.FLAG_STANDALONE, workSource, null, Process.myUid());
+            setImpl(RTC, calendar.getTimeInMillis(), 0, 0, mDateChangeSender, null, null,
+                    AlarmManager.FLAG_STANDALONE, workSource, null,
+                    Process.myUid(), "android");
         }
     }
     
@@ -2516,80 +2669,260 @@
     private final BroadcastStats getStatsLocked(PendingIntent pi) {
         String pkg = pi.getCreatorPackage();
         int uid = pi.getCreatorUid();
+        return getStatsLocked(uid, pkg);
+    }
+
+    private final BroadcastStats getStatsLocked(int uid, String pkgName) {
         ArrayMap<String, BroadcastStats> uidStats = mBroadcastStats.get(uid);
         if (uidStats == null) {
             uidStats = new ArrayMap<String, BroadcastStats>();
             mBroadcastStats.put(uid, uidStats);
         }
-        BroadcastStats bs = uidStats.get(pkg);
+        BroadcastStats bs = uidStats.get(pkgName);
         if (bs == null) {
-            bs = new BroadcastStats(uid, pkg);
-            uidStats.put(pkg, bs);
+            bs = new BroadcastStats(uid, pkgName);
+            uidStats.put(pkgName, bs);
         }
         return bs;
     }
 
-    class ResultReceiver implements PendingIntent.OnFinished {
+    class DeliveryTracker extends IAlarmCompleteListener.Stub implements PendingIntent.OnFinished {
+        private InFlight removeLocked(PendingIntent pi, Intent intent) {
+            for (int i = 0; i < mInFlight.size(); i++) {
+                if (mInFlight.get(i).mPendingIntent == pi) {
+                    return mInFlight.remove(i);
+                }
+            }
+            mLog.w("No in-flight alarm for " + pi + " " + intent);
+            return null;
+        }
+
+        private InFlight removeLocked(IBinder listener) {
+            for (int i = 0; i < mInFlight.size(); i++) {
+                if (mInFlight.get(i).mListener == listener) {
+                    return mInFlight.remove(i);
+                }
+            }
+            mLog.w("No in-flight alarm for listener " + listener);
+            return null;
+        }
+
+        private void updateStatsLocked(InFlight inflight) {
+            final long nowELAPSED = SystemClock.elapsedRealtime();
+            BroadcastStats bs = inflight.mBroadcastStats;
+            bs.nesting--;
+            if (bs.nesting <= 0) {
+                bs.nesting = 0;
+                bs.aggregateTime += nowELAPSED - bs.startTime;
+            }
+            FilterStats fs = inflight.mFilterStats;
+            fs.nesting--;
+            if (fs.nesting <= 0) {
+                fs.nesting = 0;
+                fs.aggregateTime += nowELAPSED - fs.startTime;
+            }
+            if (RECORD_ALARMS_IN_HISTORY) {
+                if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
+                    for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
+                        ActivityManagerNative.noteAlarmFinish(
+                                inflight.mPendingIntent, inflight.mWorkSource.get(wi), inflight.mTag);
+                    }
+                } else {
+                    ActivityManagerNative.noteAlarmFinish(
+                            inflight.mPendingIntent, inflight.mUid, inflight.mTag);
+                }
+            }
+        }
+
+        private void updateTrackingLocked(InFlight inflight) {
+            if (inflight != null) {
+                updateStatsLocked(inflight);
+            }
+            mBroadcastRefCount--;
+            if (mBroadcastRefCount == 0) {
+                mWakeLock.release();
+                if (mInFlight.size() > 0) {
+                    mLog.w("Finished all dispatches with " + mInFlight.size()
+                            + " remaining inflights");
+                    for (int i=0; i<mInFlight.size(); i++) {
+                        mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
+                    }
+                    mInFlight.clear();
+                }
+            } else {
+                // the next of our alarms is now in flight.  reattribute the wakelock.
+                if (mInFlight.size() > 0) {
+                    InFlight inFlight = mInFlight.get(0);
+                    setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
+                            inFlight.mAlarmType, inFlight.mTag, -1, false);
+                } else {
+                    // should never happen
+                    mLog.w("Alarm wakelock still held but sent queue empty");
+                    mWakeLock.setWorkSource(null);
+                }
+            }
+        }
+
+        /**
+         * Callback that arrives when a direct-call alarm reports that delivery has finished
+         */
+        @Override
+        public void alarmComplete(IBinder who) {
+            if (who == null) {
+                Slog.w(TAG, "Invalid alarmComplete: uid=" + Binder.getCallingUid()
+                        + " pid=" + Binder.getCallingPid());
+                return;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    mHandler.removeMessages(AlarmHandler.LISTENER_TIMEOUT, who);
+                    InFlight inflight = removeLocked(who);
+                    if (inflight != null) {
+                        if (DEBUG_LISTENER_CALLBACK) {
+                            Slog.i(TAG, "alarmComplete() from " + who);
+                        }
+                        updateTrackingLocked(inflight);
+                    } else {
+                        // Delivery timed out, and the timeout handling already took care of
+                        // updating our tracking here, so we needn't do anything further.
+                        if (DEBUG_LISTENER_CALLBACK) {
+                            Slog.i(TAG, "Late alarmComplete() from " + who);
+                        }
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        /**
+         * Callback that arrives when a PendingIntent alarm has finished delivery
+         */
+        @Override
         public void onSendFinished(PendingIntent pi, Intent intent, int resultCode,
                 String resultData, Bundle resultExtras) {
             synchronized (mLock) {
-                InFlight inflight = null;
-                for (int i=0; i<mInFlight.size(); i++) {
-                    if (mInFlight.get(i).mPendingIntent == pi) {
-                        inflight = mInFlight.remove(i);
-                        break;
-                    }
-                }
+                updateTrackingLocked(removeLocked(pi, intent));
+            }
+        }
+
+        /**
+         * Timeout of a direct-call alarm delivery
+         */
+        public void alarmTimedOut(IBinder who) {
+            synchronized (mLock) {
+                InFlight inflight = removeLocked(who);
                 if (inflight != null) {
-                    final long nowELAPSED = SystemClock.elapsedRealtime();
-                    BroadcastStats bs = inflight.mBroadcastStats;
-                    bs.nesting--;
-                    if (bs.nesting <= 0) {
-                        bs.nesting = 0;
-                        bs.aggregateTime += nowELAPSED - bs.startTime;
+                    // TODO: implement ANR policy for the target
+                    if (DEBUG_LISTENER_CALLBACK) {
+                        Slog.i(TAG, "Alarm listener " + who + " timed out in delivery");
                     }
-                    FilterStats fs = inflight.mFilterStats;
-                    fs.nesting--;
-                    if (fs.nesting <= 0) {
-                        fs.nesting = 0;
-                        fs.aggregateTime += nowELAPSED - fs.startTime;
-                    }
-                    if (RECORD_ALARMS_IN_HISTORY) {
-                        if (inflight.mWorkSource != null && inflight.mWorkSource.size() > 0) {
-                            for (int wi=0; wi<inflight.mWorkSource.size(); wi++) {
-                                ActivityManagerNative.noteAlarmFinish(
-                                        pi, inflight.mWorkSource.get(wi), inflight.mTag);
-                            }
-                        } else {
-                            ActivityManagerNative.noteAlarmFinish(
-                                    pi, -1, inflight.mTag);
-                        }
-                    }
+                    updateTrackingLocked(inflight);
                 } else {
-                    mLog.w("No in-flight alarm for " + pi + " " + intent);
+                    if (DEBUG_LISTENER_CALLBACK) {
+                        Slog.i(TAG, "Spurious timeout of listener " + who);
+                    }
                 }
-                mBroadcastRefCount--;
-                if (mBroadcastRefCount == 0) {
-                    mWakeLock.release();
-                    if (mInFlight.size() > 0) {
-                        mLog.w("Finished all broadcasts with " + mInFlight.size()
-                                + " remaining inflights");
-                        for (int i=0; i<mInFlight.size(); i++) {
-                            mLog.w("  Remaining #" + i + ": " + mInFlight.get(i));
-                        }
-                        mInFlight.clear();
+            }
+        }
+
+        /**
+         * Deliver an alarm and set up the post-delivery handling appropriately
+         */
+        public void deliverLocked(Alarm alarm, long nowELAPSED, boolean allowWhileIdle) {
+            if (alarm.operation != null) {
+                // PendingIntent alarm
+                try {
+                    alarm.operation.send(getContext(), 0,
+                            mBackgroundIntent.putExtra(
+                                    Intent.EXTRA_ALARM_COUNT, alarm.count),
+                                    mDeliveryTracker, mHandler, null,
+                                    allowWhileIdle ? mIdleOptions : null);
+                } catch (PendingIntent.CanceledException e) {
+                    if (alarm.repeatInterval > 0) {
+                        // This IntentSender is no longer valid, but this
+                        // is a repeating alarm, so toss it
+                        removeImpl(alarm.operation);
+                    }
+                }
+            } else {
+                // Direct listener callback alarm
+                try {
+                    if (DEBUG_LISTENER_CALLBACK) {
+                        Slog.v(TAG, "Alarm to uid=" + alarm.uid
+                                + " listener=" + alarm.listener.asBinder());
+                    }
+                    alarm.listener.doAlarm(this);
+                    mHandler.sendMessageDelayed(
+                            mHandler.obtainMessage(AlarmHandler.LISTENER_TIMEOUT,
+                                    alarm.listener.asBinder()),
+                            mConstants.LISTENER_TIMEOUT);
+                } catch (Exception e) {
+                    if (DEBUG_LISTENER_CALLBACK) {
+                        Slog.i(TAG, "Alarm undeliverable to listener "
+                                + alarm.listener.asBinder(), e);
+                    }
+                }
+            }
+
+            // The alarm is now in flight; now arrange wakelock and stats tracking
+            if (mBroadcastRefCount == 0) {
+                setWakelockWorkSource(alarm.operation, alarm.workSource,
+                        alarm.type, alarm.statsTag, (alarm.operation == null) ? alarm.uid : -1,
+                        true);
+                mWakeLock.acquire();
+            }
+            final InFlight inflight = new InFlight(AlarmManagerService.this,
+                    alarm.operation, alarm.listener, alarm.workSource, alarm.uid,
+                    alarm.packageName, alarm.type, alarm.statsTag, nowELAPSED);
+            mInFlight.add(inflight);
+            mBroadcastRefCount++;
+
+            if (allowWhileIdle) {
+                // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm.
+                mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED);
+                if (RECORD_DEVICE_IDLE_ALARMS) {
+                    IdleDispatchEntry ent = new IdleDispatchEntry();
+                    ent.uid = alarm.uid;
+                    ent.pkg = alarm.packageName;
+                    ent.tag = alarm.statsTag;
+                    ent.op = "DELIVER";
+                    ent.elapsedRealtime = nowELAPSED;
+                    mAllowWhileIdleDispatches.add(ent);
+                }
+            }
+
+            final BroadcastStats bs = inflight.mBroadcastStats;
+            bs.count++;
+            if (bs.nesting == 0) {
+                bs.nesting = 1;
+                bs.startTime = nowELAPSED;
+            } else {
+                bs.nesting++;
+            }
+            final FilterStats fs = inflight.mFilterStats;
+            fs.count++;
+            if (fs.nesting == 0) {
+                fs.nesting = 1;
+                fs.startTime = nowELAPSED;
+            } else {
+                fs.nesting++;
+            }
+            if (alarm.type == ELAPSED_REALTIME_WAKEUP
+                    || alarm.type == RTC_WAKEUP) {
+                bs.numWakeup++;
+                fs.numWakeup++;
+                if (alarm.workSource != null && alarm.workSource.size() > 0) {
+                    for (int wi=0; wi<alarm.workSource.size(); wi++) {
+                        ActivityManagerNative.noteWakeupAlarm(
+                                alarm.operation, alarm.workSource.get(wi),
+                                alarm.workSource.getName(wi), alarm.statsTag);
                     }
                 } else {
-                    // the next of our alarms is now in flight.  reattribute the wakelock.
-                    if (mInFlight.size() > 0) {
-                        InFlight inFlight = mInFlight.get(0);
-                        setWakelockWorkSource(inFlight.mPendingIntent, inFlight.mWorkSource,
-                                inFlight.mAlarmType, inFlight.mTag, false);
-                    } else {
-                        // should never happen
-                        mLog.w("Alarm wakelock still held but sent queue empty");
-                        mWakeLock.setWorkSource(null);
-                    }
+                    ActivityManagerNative.noteWakeupAlarm(
+                            alarm.operation, -1, alarm.packageName, alarm.statsTag);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index c373fb8..96c1e2a 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -39,7 +39,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.media.AudioAttributes;
 import android.os.AsyncTask;
 import android.os.Binder;
@@ -263,12 +262,12 @@
                 Iterator<Ops> it = pkgs.values().iterator();
                 while (it.hasNext()) {
                     Ops ops = it.next();
-                    int curUid;
+                    int curUid = -1;
                     try {
-                        curUid = mContext.getPackageManager().getPackageUid(ops.packageName,
+                        curUid = AppGlobals.getPackageManager().getPackageUidEtc(ops.packageName,
+                                PackageManager.GET_UNINSTALLED_PACKAGES,
                                 UserHandle.getUserId(ops.uidState.uid));
-                    } catch (NameNotFoundException e) {
-                        curUid = -1;
+                    } catch (RemoteException ignored) {
                     }
                     if (curUid != ops.uidState.uid) {
                         Slog.i(TAG, "Pruning old package " + ops.packageName
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 2eeaec9..61fe62f 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -19,6 +19,8 @@
 import android.database.ContentObserver;
 import android.os.BatteryStats;
 
+import android.os.ResultReceiver;
+import android.os.ShellCommand;
 import com.android.internal.app.IBatteryStats;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.lights.Light;
@@ -96,7 +98,6 @@
     // discharge stats before the device dies.
     private int mCriticalBatteryLevel;
 
-    private static final int DUMP_MAX_LENGTH = 24 * 1024;
     private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
 
     private static final String DUMPSYS_DATA_PATH = "/data/system/";
@@ -106,6 +107,7 @@
 
     private final Context mContext;
     private final IBatteryStats mBatteryStats;
+    BinderService mBinderService;
     private final Handler mHandler;
 
     private final Object mLock = new Object();
@@ -162,7 +164,18 @@
 
         // watch for invalid charger messages if the invalid_charger switch exists
         if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
-            mInvalidChargerObserver.startObserving(
+            UEventObserver invalidChargerObserver = new UEventObserver() {
+                @Override
+                public void onUEvent(UEvent event) {
+                    final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
+                    synchronized (mLock) {
+                        if (mInvalidCharger != invalidCharger) {
+                            mInvalidCharger = invalidCharger;
+                        }
+                    }
+                }
+            };
+            invalidChargerObserver.startObserving(
                     "DEVPATH=/devices/virtual/switch/invalid_charger");
         }
     }
@@ -178,7 +191,8 @@
             // Should never happen.
         }
 
-        publishBinderService("battery", new BinderService());
+        mBinderService = new BinderService();
+        publishBinderService("battery", mBinderService);
         publishLocalService(BatteryManagerInternal.class, new LocalService());
     }
 
@@ -593,7 +607,6 @@
             } catch (NumberFormatException e) {
                 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
                         durationThresholdString + " or " + dischargeThresholdString);
-                return;
             }
         }
     }
@@ -616,7 +629,133 @@
         }
     }
 
-    private void dumpInternal(PrintWriter pw, String[] args) {
+    class Shell extends ShellCommand {
+        @Override
+        public int onCommand(String cmd) {
+            return onShellCommand(this, cmd);
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            dumpHelp(pw);
+        }
+    }
+
+    static void dumpHelp(PrintWriter pw) {
+        pw.println("Battery service (battery) commands:");
+        pw.println("  help");
+        pw.println("    Print this help text.");
+        pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
+        pw.println("    Force a battery property value, freezing battery state.");
+        pw.println("  unplug");
+        pw.println("    Force battery unplugged, freezing battery state.");
+        pw.println("  reset");
+        pw.println("    Unfreeze battery state, returning to current hardware values.");
+    }
+
+    int onShellCommand(Shell shell, String cmd) {
+        if (cmd == null) {
+            return shell.handleDefaultCommands(cmd);
+        }
+        PrintWriter pw = shell.getOutPrintWriter();
+        switch (cmd) {
+            case "unplug": {
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.DEVICE_POWER, null);
+                if (!mUpdatesStopped) {
+                    mLastBatteryProps.set(mBatteryProps);
+                }
+                mBatteryProps.chargerAcOnline = false;
+                mBatteryProps.chargerUsbOnline = false;
+                mBatteryProps.chargerWirelessOnline = false;
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mUpdatesStopped = true;
+                    processValuesLocked(false);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            } break;
+            case "set": {
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.DEVICE_POWER, null);
+                final String key = shell.getNextArg();
+                if (key == null) {
+                    pw.println("No property specified");
+                    return -1;
+
+                }
+                final String value = shell.getNextArg();
+                if (value == null) {
+                    pw.println("No value specified");
+                    return -1;
+
+                }
+                try {
+                    if (!mUpdatesStopped) {
+                        mLastBatteryProps.set(mBatteryProps);
+                    }
+                    boolean update = true;
+                    switch (key) {
+                        case "ac":
+                            mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
+                            break;
+                        case "usb":
+                            mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
+                            break;
+                        case "wireless":
+                            mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
+                            break;
+                        case "status":
+                            mBatteryProps.batteryStatus = Integer.parseInt(value);
+                            break;
+                        case "level":
+                            mBatteryProps.batteryLevel = Integer.parseInt(value);
+                            break;
+                        case "invalid":
+                            mInvalidCharger = Integer.parseInt(value);
+                            break;
+                        default:
+                            pw.println("Unknown set option: " + key);
+                            update = false;
+                            break;
+                    }
+                    if (update) {
+                        long ident = Binder.clearCallingIdentity();
+                        try {
+                            mUpdatesStopped = true;
+                            processValuesLocked(false);
+                        } finally {
+                            Binder.restoreCallingIdentity(ident);
+                        }
+                    }
+                } catch (NumberFormatException ex) {
+                    pw.println("Bad value: " + value);
+                    return -1;
+                }
+            } break;
+            case "reset": {
+                getContext().enforceCallingOrSelfPermission(
+                        android.Manifest.permission.DEVICE_POWER, null);
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    if (mUpdatesStopped) {
+                        mUpdatesStopped = false;
+                        mBatteryProps.set(mLastBatteryProps);
+                        processValuesLocked(false);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            } break;
+            default:
+                return shell.handleDefaultCommands(cmd);
+        }
+        return 0;
+    }
+
+    private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
         synchronized (mLock) {
             if (args == null || args.length == 0 || "-a".equals(args[0])) {
                 pw.println("Current Battery Service state:");
@@ -635,91 +774,13 @@
                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);
                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);
                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
-
-            } else if ("unplug".equals(args[0])) {
-                if (!mUpdatesStopped) {
-                    mLastBatteryProps.set(mBatteryProps);
-                }
-                mBatteryProps.chargerAcOnline = false;
-                mBatteryProps.chargerUsbOnline = false;
-                mBatteryProps.chargerWirelessOnline = false;
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    mUpdatesStopped = true;
-                    processValuesLocked(false);
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
-
-            } else if (args.length == 3 && "set".equals(args[0])) {
-                String key = args[1];
-                String value = args[2];
-                try {
-                    if (!mUpdatesStopped) {
-                        mLastBatteryProps.set(mBatteryProps);
-                    }
-                    boolean update = true;
-                    if ("ac".equals(key)) {
-                        mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
-                    } else if ("usb".equals(key)) {
-                        mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
-                    } else if ("wireless".equals(key)) {
-                        mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
-                    } else if ("status".equals(key)) {
-                        mBatteryProps.batteryStatus = Integer.parseInt(value);
-                    } else if ("level".equals(key)) {
-                        mBatteryProps.batteryLevel = Integer.parseInt(value);
-                    } else if ("invalid".equals(key)) {
-                        mInvalidCharger = Integer.parseInt(value);
-                    } else {
-                        pw.println("Unknown set option: " + key);
-                        update = false;
-                    }
-                    if (update) {
-                        long ident = Binder.clearCallingIdentity();
-                        try {
-                            mUpdatesStopped = true;
-                            processValuesLocked(false);
-                        } finally {
-                            Binder.restoreCallingIdentity(ident);
-                        }
-                    }
-                } catch (NumberFormatException ex) {
-                    pw.println("Bad value: " + value);
-                }
-
-            } else if (args.length == 1 && "reset".equals(args[0])) {
-                long ident = Binder.clearCallingIdentity();
-                try {
-                    if (mUpdatesStopped) {
-                        mUpdatesStopped = false;
-                        mBatteryProps.set(mLastBatteryProps);
-                        processValuesLocked(false);
-                    }
-                } finally {
-                    Binder.restoreCallingIdentity(ident);
-                }
             } else {
-                pw.println("Dump current battery state, or:");
-                pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
-                pw.println("  unplug");
-                pw.println("  reset");
+                Shell shell = new Shell();
+                shell.exec(mBinderService, null, fd, null, args, new ResultReceiver(null));
             }
         }
     }
 
-    private final UEventObserver mInvalidChargerObserver = new UEventObserver() {
-        @Override
-        public void onUEvent(UEventObserver.UEvent event) {
-            final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
-            synchronized (mLock) {
-                if (mInvalidCharger != invalidCharger) {
-                    mInvalidCharger = invalidCharger;
-                }
-            }
-        }
-    };
-
     private final class Led {
         private final Light mBatteryLight;
 
@@ -776,8 +837,7 @@
     }
 
     private final class BatteryListener extends IBatteryPropertiesListener.Stub {
-        @Override
-        public void batteryPropertiesChanged(BatteryProperties props) {
+        @Override public void batteryPropertiesChanged(BatteryProperties props) {
             final long identity = Binder.clearCallingIdentity();
             try {
                 BatteryService.this.update(props);
@@ -788,8 +848,7 @@
     }
 
     private final class BinderService extends Binder {
-        @Override
-        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                     != PackageManager.PERMISSION_GRANTED) {
 
@@ -799,7 +858,12 @@
                 return;
             }
 
-            dumpInternal(pw, args);
+            dumpInternal(fd, pw, args);
+        }
+
+        @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
+                FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+            (new Shell()).exec(this, in, out, err, args, resultReceiver);
         }
     }
 
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 496e4df..927b995 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1500,7 +1500,7 @@
                 mState = STATE_SENSING;
                 if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
                 EventLogTags.writeDeviceIdle(mState, "step");
-                cancelAlarmLocked();
+                scheduleAlarmLocked(mConstants.SENSING_TIMEOUT, false);
                 cancelLocatingLocked();
                 mAnyMotionDetector.checkForAnyMotion();
                 mNotMoving = false;
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 6b34612..1ff13b2 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3824,7 +3824,6 @@
         boolean isPermitted =
                 isPermitted(opPackageName, callingUid, Manifest.permission.GET_ACCOUNTS,
                         Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
-        Log.i(TAG, String.format("getTypesVisibleToCaller: isPermitted? %s", isPermitted));
         return getTypesForCaller(callingUid, userId, isPermitted);
     }
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 465118c2..df6b1d6 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -355,7 +355,8 @@
 
         final ServiceMap smap = getServiceMap(r.userId);
         boolean addToStarting = false;
-        if (!callerFg && r.app == null && mAm.mStartedUsers.get(r.userId) != null) {
+        if (!callerFg && r.app == null
+                && mAm.mUserController.hasStartedUserState(r.userId)) {
             ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false);
             if (proc == null || proc.curProcState > ActivityManager.PROCESS_STATE_RECEIVER) {
                 // If this is not coming from a foreground caller, then we may want
@@ -1401,7 +1402,7 @@
 
         // Make sure that the user who owns this service is started.  If not,
         // we don't want to allow it to run.
-        if (mAm.mStartedUsers.get(r.userId) == null) {
+        if (!mAm.mUserController.hasStartedUserState(r.userId)) {
             String msg = "Unable to launch app "
                     + r.appInfo.packageName + "/"
                     + r.appInfo.uid + " for service "
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index bb1b6b8..5aab804 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -24,6 +24,7 @@
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
 import static android.app.ActivityManager.INVALID_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -68,18 +69,19 @@
 import android.os.BatteryStats;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
+import android.os.ResultReceiver;
 import android.os.Trace;
 import android.os.TransactionTooLargeException;
 import android.os.WorkSource;
 import android.os.storage.IMountService;
 import android.os.storage.MountServiceInternal;
 import android.os.storage.StorageManager;
+import android.provider.Settings.Global;
 import android.service.voice.IVoiceInteractionSession;
 import android.service.voice.VoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DebugUtils;
-import android.util.SparseIntArray;
 import android.view.Display;
 
 import com.android.internal.R;
@@ -205,7 +207,6 @@
 import android.os.IBinder;
 import android.os.IPermissionController;
 import android.os.IProcessInfoService;
-import android.os.IRemoteCallback;
 import android.os.IUserManager;
 import android.os.Looper;
 import android.os.Message;
@@ -370,17 +371,10 @@
     // How long we wait until we timeout on key dispatching during instrumentation.
     static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
 
-    // Amount of time we wait for observers to handle a user switch before
-    // giving up on them and unfreezing the screen.
-    static final int USER_SWITCH_TIMEOUT = 2*1000;
-
     // This is the amount of time an app needs to be running a foreground service before
     // we will consider it to be doing interaction for usage stats.
     static final int SERVICE_USAGE_INTERACTION_TIME = 30*60*1000;
 
-    // Maximum number of users we allow to be running at a time.
-    static final int MAX_RUNNING_USERS = 3;
-
     // How long to wait in getAssistContextExtras for the activity and foreground services
     // to respond with the result.
     static final int PENDING_ASSIST_EXTRAS_TIMEOUT = 500;
@@ -505,6 +499,8 @@
      */
     String mDeviceOwnerName;
 
+    final UserController mUserController;
+
     public class PendingAssistExtras extends Binder implements Runnable {
         public final ActivityRecord activity;
         public final Bundle extras;
@@ -707,32 +703,6 @@
     final SparseArray<UidRecord> mActiveUids = new SparseArray<>();
 
     /**
-     * Which users have been started, so are allowed to run code.
-     */
-    final SparseArray<UserState> mStartedUsers = new SparseArray<>();
-
-    /**
-     * LRU list of history of current users.  Most recently current is at the end.
-     */
-    final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
-
-    /**
-     * Constant array of the users that are currently started.
-     */
-    int[] mStartedUserArray = new int[] { 0 };
-
-    /**
-     * Registered observers of the user switching mechanics.
-     */
-    final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
-            = new RemoteCallbackList<IUserSwitchObserver>();
-
-    /**
-     * Currently active user switch.
-     */
-    Object mCurUserSwitchCallback;
-
-    /**
      * Packages that the user has asked to have run in screen size
      * compatibility mode instead of filling the screen.
      */
@@ -1221,6 +1191,7 @@
     String mOrigDebugApp = null;
     boolean mOrigWaitForDebugger = false;
     boolean mAlwaysFinishActivities = false;
+    boolean mForceResizableActivites;
     IActivityController mController = null;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
@@ -1300,19 +1271,6 @@
 
     final ActivityThread mSystemThread;
 
-    // Holds the current foreground user's id
-    int mCurrentUserId = 0;
-    // Holds the target user's id during a user switch
-    int mTargetUserId = UserHandle.USER_NULL;
-    // If there are multiple profiles for the current user, their ids are here
-    // Currently only the primary user can have managed profiles
-    int[] mCurrentProfileIds = new int[] {}; // Accessed by ActivityStack
-
-    /**
-     * Mapping from each known user ID to the profile group ID it is associated with.
-     */
-    SparseIntArray mUserProfileGroupIdsSelfLocked = new SparseIntArray();
-
     private UserManagerService mUserManager;
 
     private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1442,7 +1400,7 @@
                     boolean isBackground = (UserHandle.getAppId(proc.uid)
                             >= Process.FIRST_APPLICATION_UID
                             && proc.pid != MY_PID);
-                    for (int userId : mCurrentProfileIds) {
+                    for (int userId : mUserController.mCurrentProfileIds) {
                         isBackground &= (proc.userId != userId);
                     }
                     if (isBackground && !showBackground) {
@@ -1829,15 +1787,15 @@
                 break;
             }
             case REPORT_USER_SWITCH_MSG: {
-                dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
+                mUserController.dispatchUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
                 break;
             }
             case CONTINUE_USER_SWITCH_MSG: {
-                continueUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
+                mUserController.continueUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
                 break;
             }
             case USER_SWITCH_TIMEOUT_MSG: {
-                timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
+                mUserController.timeoutUserSwitch((UserState) msg.obj, msg.arg1, msg.arg2);
                 break;
             }
             case IMMERSIVE_MODE_LOCK_MSG: {
@@ -1866,7 +1824,7 @@
             }
             case START_PROFILES_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    startProfilesLocked();
+                    mUserController.startProfilesLocked();
                 }
                 break;
             }
@@ -2057,14 +2015,14 @@
                 }
             } break;
             case FOREGROUND_PROFILE_CHANGED_MSG: {
-                dispatchForegroundProfileChanged(msg.arg1);
+                mUserController.dispatchForegroundProfileChanged(msg.arg1);
             } break;
             case REPORT_TIME_TRACKER_MSG: {
                 AppTimeTracker tracker = (AppTimeTracker)msg.obj;
                 tracker.deliverResult(mContext);
             } break;
             case REPORT_USER_SWITCH_COMPLETE_MSG: {
-                dispatchUserSwitchComplete(msg.arg1);
+                mUserController.dispatchUserSwitchComplete(msg.arg1);
             } break;
             case SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG: {
                 IUiAutomationConnection connection = (IUiAutomationConnection) msg.obj;
@@ -2386,10 +2344,7 @@
 
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
-        // User 0 is the first and only user that runs at boot.
-        mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
-        mUserLru.add(UserHandle.USER_SYSTEM);
-        updateStartedUserArrayLocked();
+        mUserController = new UserController(this);
 
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
             ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -3890,8 +3845,8 @@
             Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
             int startFlags, ProfilerInfo profilerInfo, Bundle options) {
         return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
-            resultWho, requestCode, startFlags, profilerInfo, options,
-            UserHandle.getCallingUserId());
+                resultWho, requestCode, startFlags, profilerInfo, options,
+                UserHandle.getCallingUserId());
     }
 
     @Override
@@ -4198,7 +4153,12 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        return startActivityFromRecentsInner(taskId, launchStackId, options);
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            return startActivityFromRecentsInner(taskId, launchStackId, options);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
     }
 
     final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle options) {
@@ -4220,8 +4180,12 @@
             }
 
             if (launchStackId != INVALID_STACK_ID && task.stack.mStackId != launchStackId) {
-                mStackSupervisor.moveTaskToStackUncheckedLocked(
-                        task, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents");
+                if (launchStackId == DOCKED_STACK_ID && options != null) {
+                    ActivityOptions activityOptions = new ActivityOptions(options);
+                    mWindowManager.setDockedStackCreateMode(activityOptions.getDockCreateMode());
+                }
+                mStackSupervisor.moveTaskToStackLocked(
+                        taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents");
             }
 
             if (task.getRootActivity() != null) {
@@ -5566,16 +5530,6 @@
                 null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
     }
 
-    private void forceStopUserLocked(int userId, String reason) {
-        forceStopPackageLocked(null, -1, false, false, true, false, false, userId, reason);
-        Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
-        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                | Intent.FLAG_RECEIVER_FOREGROUND);
-        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        broadcastIntentLocked(null, null, intent,
-                null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
-    }
 
     private final boolean killPackageProcessesLocked(String packageName, int appId,
             int userId, int minOomAdj, boolean callerWillRestart, boolean allowRestart,
@@ -5739,7 +5693,7 @@
 
     }
 
-    private final boolean forceStopPackageLocked(String packageName, int appId,
+    final boolean forceStopPackageLocked(String packageName, int appId,
             boolean callerWillRestart, boolean purgeCache, boolean doit,
             boolean evenPersistent, boolean uninstalling, int userId, String reason) {
         int i;
@@ -6460,32 +6414,18 @@
                     || "".equals(SystemProperties.get("vold.encrypt_progress"))) {
                     SystemProperties.set("dev.bootcomplete", "1");
                 }
-                for (int i=0; i<mStartedUsers.size(); i++) {
-                    UserState uss = mStartedUsers.valueAt(i);
-                    if (uss.mState == UserState.STATE_BOOTING) {
-                        uss.mState = UserState.STATE_RUNNING;
-                        final int userId = mStartedUsers.keyAt(i);
-                        Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
-                        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
-                        broadcastIntentLocked(null, null, intent, null,
-                                new IIntentReceiver.Stub() {
-                                    @Override
-                                    public void performReceive(Intent intent, int resultCode,
-                                            String data, Bundle extras, boolean ordered,
-                                            boolean sticky, int sendingUser) {
-                                        synchronized (ActivityManagerService.this) {
-                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
-                                                    true, false);
-                                        }
-                                    }
-                                },
-                                0, null, null,
-                                new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                                AppOpsManager.OP_NONE, null, true, false,
-                                MY_PID, Process.SYSTEM_UID, userId);
-                    }
-                }
+                mUserController.sendBootCompletedLocked(
+                        new IIntentReceiver.Stub() {
+                            @Override
+                            public void performReceive(Intent intent, int resultCode,
+                                    String data, Bundle extras, boolean ordered,
+                                    boolean sticky, int sendingUser) {
+                                synchronized (ActivityManagerService.this) {
+                                    requestPssAllProcsLocked(SystemClock.uptimeMillis(),
+                                            true, false);
+                                }
+                            }
+                        });
                 scheduleStartProfilesLocked();
             }
         }
@@ -6587,7 +6527,7 @@
 
     @Override
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations) {
+            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
                 + horizontalSizeConfiguration + " " + verticalSizeConfigurations);
         synchronized (this) {
@@ -6597,7 +6537,7 @@
                         + "found for: " + token);
             }
             record.setSizeConfigurations(horizontalSizeConfiguration,
-                    verticalSizeConfigurations);
+                    verticalSizeConfigurations, smallestSizeConfigurations);
         }
     }
 
@@ -8711,9 +8651,10 @@
                 // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
                 //   that task to freeform
                 // - otherwise the task is not moved
-                // Note it's not allowed to resize a home stack task, or a docked task.
+                // Note it's not allowed to resize a home, docked, or pinned stack task.
                 int stackId = task.stack.mStackId;
-                if (stackId == HOME_STACK_ID || stackId == DOCKED_STACK_ID) {
+                if (stackId == HOME_STACK_ID || stackId == DOCKED_STACK_ID
+                        || stackId == PINNED_STACK_ID) {
                     throw new IllegalArgumentException("trying to resizeTask on a "
                             + "home or docked task");
                 }
@@ -9098,7 +9039,8 @@
                 }
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
                         + " to stackId=" + stackId);
-                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS);
+                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS,
+                        "moveActivityToStack");
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9118,7 +9060,8 @@
             try {
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToStack: moving task=" + taskId
                         + " to stackId=" + stackId + " toTop=" + toTop);
-                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS);
+                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS,
+                        "moveTaskToStack");
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9147,7 +9090,30 @@
                         + " to createMode=" + createMode + " toTop=" + toTop);
                 mWindowManager.setDockedStackCreateMode(createMode);
                 mStackSupervisor.moveTaskToStackLocked(
-                        taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS);
+                        taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack");
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    /**
+     * Moves the top activity in the input stackId to the pinned stack.
+     *
+     * @param stackId Id of stack to move the top activity to pinned stack.
+     * @param bounds Bounds to use for pinned stack.
+     *
+     * @return True if the top activity of the input stack was successfully moved to the pinned
+     *          stack.
+     */
+    @Override
+    public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "moveTopActivityToPinnedStack()");
+        synchronized (this) {
+            long ident = Binder.clearCallingIdentity();
+            try {
+                return mStackSupervisor.moveTopStackActivityToPinnedStackLocked(stackId, bounds);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -9492,7 +9458,7 @@
         boolean checkedGrants = false;
         if (checkUser) {
             // Looking for cross-user grants before enforcing the typical cross-users permissions
-            int tmpTargetUserId = unsafeConvertIncomingUser(userId);
+            int tmpTargetUserId = unsafeConvertIncomingUserLocked(userId);
             if (tmpTargetUserId != UserHandle.getUserId(callingUid)) {
                 if (checkAuthorityGrants(callingUid, cpi, tmpTargetUserId, checkUser)) {
                     return null;
@@ -10338,7 +10304,9 @@
         int callingPid = Binder.getCallingPid();
         long ident = 0;
         boolean clearedIdentity = false;
-        userId = unsafeConvertIncomingUser(userId);
+        synchronized (this) {
+            userId = unsafeConvertIncomingUserLocked(userId);
+        }
         if (canClearIdentity(callingPid, callingUid, userId)) {
             clearedIdentity = true;
             ident = Binder.clearCallingIdentity();
@@ -11005,8 +10973,9 @@
 
     @Override
     public boolean isAssistDataAllowedOnCurrentActivity() {
-        int userId = mCurrentUserId;
+        int userId;
         synchronized (this) {
+            userId = mUserController.mCurrentUserId;
             ActivityRecord activity = getFocusedStack().topActivity();
             if (activity == null) {
                 return false;
@@ -11395,7 +11364,7 @@
     }
 
     public void noteWakeupAlarm(IIntentSender sender, int sourceUid, String sourcePkg, String tag) {
-        if (!(sender instanceof PendingIntentRecord)) {
+        if (sender != null && !(sender instanceof PendingIntentRecord)) {
             return;
         }
         final PendingIntentRecord rec = (PendingIntentRecord)sender;
@@ -11404,7 +11373,12 @@
             if (mBatteryStatsService.isOnBattery()) {
                 mBatteryStatsService.enforceCallingPermission();
                 int MY_UID = Binder.getCallingUid();
-                int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                final int uid;
+                if (sender == null) {
+                    uid = sourceUid;
+                } else {
+                    uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+                }
                 BatteryStatsImpl.Uid.Pkg pkg =
                     stats.getPackageStatsLocked(sourceUid >= 0 ? sourceUid : uid,
                             sourcePkg != null ? sourcePkg : rec.key.packageName);
@@ -11414,7 +11388,7 @@
     }
 
     public void noteAlarmStart(IIntentSender sender, int sourceUid, String tag) {
-        if (!(sender instanceof PendingIntentRecord)) {
+        if (sender != null && !(sender instanceof PendingIntentRecord)) {
             return;
         }
         final PendingIntentRecord rec = (PendingIntentRecord)sender;
@@ -11422,13 +11396,18 @@
         synchronized (stats) {
             mBatteryStatsService.enforceCallingPermission();
             int MY_UID = Binder.getCallingUid();
-            int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            final int uid;
+            if (sender == null) {
+                uid = sourceUid;
+            } else {
+                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            }
             mBatteryStatsService.noteAlarmStart(tag, sourceUid >= 0 ? sourceUid : uid);
         }
     }
 
     public void noteAlarmFinish(IIntentSender sender, int sourceUid, String tag) {
-        if (!(sender instanceof PendingIntentRecord)) {
+        if (sender != null && !(sender instanceof PendingIntentRecord)) {
             return;
         }
         final PendingIntentRecord rec = (PendingIntentRecord)sender;
@@ -11436,7 +11415,12 @@
         synchronized (stats) {
             mBatteryStatsService.enforceCallingPermission();
             int MY_UID = Binder.getCallingUid();
-            int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            final int uid;
+            if (sender == null) {
+                uid = sourceUid;
+            } else {
+                uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
+            }
             mBatteryStatsService.noteAlarmFinish(tag, sourceUid >= 0 ? sourceUid : uid);
         }
     }
@@ -11683,14 +11667,17 @@
 
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
-        String debugApp = Settings.Global.getString(
-            resolver, Settings.Global.DEBUG_APP);
+        String debugApp = Settings.Global.getString(resolver, Settings.Global.DEBUG_APP);
         boolean waitForDebugger = Settings.Global.getInt(
             resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
         boolean alwaysFinishActivities = Settings.Global.getInt(
             resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
         boolean forceRtl = Settings.Global.getInt(
                 resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
+        int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
+        boolean forceResizable = Settings.Global.getInt(
+                resolver, Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES,
+                defaultForceResizable) != 0;
         // Transfer any global setting for forcing RTL layout, into a System Property
         SystemProperties.set(Settings.Global.DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
 
@@ -11705,6 +11692,7 @@
             mDebugApp = mOrigDebugApp = debugApp;
             mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
             mAlwaysFinishActivities = alwaysFinishActivities;
+            mForceResizableActivites = forceResizable;
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
             updateConfigurationLocked(configuration, null, true);
@@ -11929,7 +11917,7 @@
 
             // Make sure we have the current profile info, since it is needed for
             // security checks.
-            updateCurrentProfileIdsLocked();
+            mUserController.updateCurrentProfileIdsLocked();
 
             mRecentTasks.clear();
             mRecentTasks.addAll(mTaskPersister.restoreTasksLocked(
@@ -12036,18 +12024,20 @@
 
         retrieveSettings();
         loadResourcesOnSystemReady();
-
+        final int currentUserId;
         synchronized (this) {
+            currentUserId = mUserController.mCurrentUserId;
             readGrantedUriPermissionsLocked();
         }
 
         if (goingCallback != null) goingCallback.run();
 
+
         mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
-                Integer.toString(mCurrentUserId), mCurrentUserId);
+                Integer.toString(currentUserId), currentUserId);
         mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_FOREGROUND_START,
-                Integer.toString(mCurrentUserId), mCurrentUserId);
-        mSystemServiceManager.startUser(mCurrentUserId);
+                Integer.toString(currentUserId), currentUserId);
+        mSystemServiceManager.startUser(currentUserId);
 
         synchronized (this) {
             if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
@@ -12075,7 +12065,7 @@
 
             // Start up initial activity.
             mBooting = true;
-            startHomeActivityLocked(mCurrentUserId, "systemReady");
+            startHomeActivityLocked(currentUserId, "systemReady");
 
             try {
                 if (AppGlobals.getPackageManager().hasSystemUidErrors()) {
@@ -12096,13 +12086,14 @@
                 Intent intent = new Intent(Intent.ACTION_USER_STARTED);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
-                intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                        null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
+                        null, false, false, MY_PID, Process.SYSTEM_UID,
+                        currentUserId);
                 intent = new Intent(Intent.ACTION_USER_STARTING);
                 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, currentUserId);
                 broadcastIntentLocked(null, null, intent,
                         null, new IIntentReceiver.Stub() {
                             @Override
@@ -12119,7 +12110,7 @@
                 Binder.restoreCallingIdentity(ident);
             }
             mStackSupervisor.resumeTopActivitiesLocked();
-            sendUserSwitchBroadcastsLocked(-1, mCurrentUserId);
+            sendUserSwitchBroadcastsLocked(-1, currentUserId);
         }
     }
 
@@ -12131,7 +12122,8 @@
             AppsQueryHelper queryHelper = new AppsQueryHelper(mContext);
             Set<String> enableApps = new HashSet<>();
             enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
-                            | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM,
+                            | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM
+                            | AppsQueryHelper.GET_DEFAULT_IMES,
                             /* systemAppsOnly */ true, UserHandle.SYSTEM));
             ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
             enableApps.addAll(wlApps);
@@ -12318,7 +12310,7 @@
         // launching the report UI under a different user.
         app.errorReportReceiver = null;
 
-        for (int userId : mCurrentProfileIds) {
+        for (int userId : mUserController.mCurrentProfileIds) {
             if (app.userId == userId) {
                 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
                         mContext, app.info.packageName, app.info.flags);
@@ -13107,6 +13099,13 @@
     }
 
     @Override
+    public void onShellCommand(FileDescriptor in, FileDescriptor out,
+            FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
+        (new ActivityManagerShellCommand(this, false)).exec(
+                this, in, out, err, args, resultReceiver);
+    }
+
+    @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (checkCallingPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -13143,34 +13142,7 @@
                 }
                 dumpClient = true;
             } else if ("-h".equals(opt)) {
-                pw.println("Activity manager dump options:");
-                pw.println("  [-a] [-c] [-p package] [-h] [cmd] ...");
-                pw.println("  cmd may be one of:");
-                pw.println("    a[ctivities]: activity stack state");
-                pw.println("    r[recents]: recent activities state");
-                pw.println("    b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state");
-                pw.println("    i[ntents] [PACKAGE_NAME]: pending intent state");
-                pw.println("    p[rocesses] [PACKAGE_NAME]: process state");
-                pw.println("    o[om]: out of memory management");
-                pw.println("    perm[issions]: URI permission grant state");
-                pw.println("    prov[iders] [COMP_SPEC ...]: content provider state");
-                pw.println("    provider [COMP_SPEC]: provider client-side state");
-                pw.println("    s[ervices] [COMP_SPEC ...]: service state");
-                pw.println("    as[sociations]: tracked app associations");
-                pw.println("    service [COMP_SPEC]: service client-side state");
-                pw.println("    package [PACKAGE_NAME]: all state related to given package");
-                pw.println("    all: dump all activities");
-                pw.println("    top: dump the top activity");
-                pw.println("    write: write all pending state to storage");
-                pw.println("    track-associations: enable association tracking");
-                pw.println("    untrack-associations: disable and clear association tracking");
-                pw.println("  cmd may also be a COMP_SPEC to dump activities.");
-                pw.println("  COMP_SPEC may be a component name (com.foo/.myApp),");
-                pw.println("    a partial substring in a component name, a");
-                pw.println("    hex object identifier.");
-                pw.println("  -a: include all available server state.");
-                pw.println("  -c: include client state.");
-                pw.println("  -p: limit output to given package.");
+                ActivityManagerShellCommand.dumpHelp(pw, true);
                 return;
             } else {
                 pw.println("Unknown argument: " + opt + "; use -h for help");
@@ -13307,36 +13279,15 @@
                 synchronized (this) {
                     mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
-            } else if ("write".equals(cmd)) {
-                mTaskPersister.flush();
-                pw.println("All tasks persisted.");
-                return;
-            } else if ("track-associations".equals(cmd)) {
-                synchronized (this) {
-                    if (!mTrackingAssociations) {
-                        mTrackingAssociations = true;
-                        pw.println("Association tracking started.");
-                    } else {
-                        pw.println("Association tracking already enabled.");
-                    }
-                }
-                return;
-            } else if ("untrack-associations".equals(cmd)) {
-                synchronized (this) {
-                    if (mTrackingAssociations) {
-                        mTrackingAssociations = false;
-                        mAssociations.clear();
-                        pw.println("Association tracking stopped.");
-                    } else {
-                        pw.println("Association tracking not running.");
-                    }
-                }
-                return;
             } else {
                 // Dumping a single activity?
                 if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
-                    pw.println("Bad activity command, or no activities match: " + cmd);
-                    pw.println("Use -h for help.");
+                    ActivityManagerShellCommand shell = new ActivityManagerShellCommand(this, true);
+                    int res = shell.exec(this, null, fd, null, args, new ResultReceiver(null));
+                    if (res < 0) {
+                        pw.println("Bad activity command, or no activities match: " + cmd);
+                        pw.println("Use -h for help.");
+                    }
                 }
             }
             if (!more) {
@@ -13587,17 +13538,34 @@
         }
 
         if (mActiveUids.size() > 0) {
-            if (needSep) {
-                pw.println();
+            boolean printed = false;
+            int whichAppId = -1;
+            if (dumpPackage != null) {
+                try {
+                    ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
+                            dumpPackage, 0);
+                    whichAppId = UserHandle.getAppId(info.uid);
+                } catch (NameNotFoundException e) {
+                    e.printStackTrace();
+                }
             }
-            pw.println("  UID states:");
             for (int i=0; i<mActiveUids.size(); i++) {
                 UidRecord uidRec = mActiveUids.valueAt(i);
+                if (dumpPackage != null && UserHandle.getAppId(uidRec.uid) != whichAppId) {
+                    continue;
+                }
+                if (!printed) {
+                    printed = true;
+                    if (needSep) {
+                        pw.println();
+                    }
+                    pw.println("  UID states:");
+                    needSep = true;
+                    printedAnything = true;
+                }
                 pw.print("    UID "); UserHandle.formatUid(pw, uidRec.uid);
                 pw.print(": "); pw.println(uidRec);
             }
-            needSep = true;
-            printedAnything = true;
         }
 
         if (mLruProcesses.size() > 0) {
@@ -13775,38 +13743,7 @@
         if (dumpPackage == null) {
             pw.println();
             needSep = false;
-            pw.println("  mStartedUsers:");
-            for (int i=0; i<mStartedUsers.size(); i++) {
-                UserState uss = mStartedUsers.valueAt(i);
-                pw.print("    User #"); pw.print(uss.mHandle.getIdentifier());
-                        pw.print(": "); uss.dump("", pw);
-            }
-            pw.print("  mStartedUserArray: [");
-            for (int i=0; i<mStartedUserArray.length; i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(mStartedUserArray[i]);
-            }
-            pw.println("]");
-            pw.print("  mUserLru: [");
-            for (int i=0; i<mUserLru.size(); i++) {
-                if (i > 0) pw.print(", ");
-                pw.print(mUserLru.get(i));
-            }
-            pw.println("]");
-            if (dumpAll) {
-                pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
-            }
-            synchronized (mUserProfileGroupIdsSelfLocked) {
-                if (mUserProfileGroupIdsSelfLocked.size() > 0) {
-                    pw.println("  mUserProfileGroupIds:");
-                    for (int i=0; i<mUserProfileGroupIdsSelfLocked.size(); i++) {
-                        pw.print("    User #");
-                        pw.print(mUserProfileGroupIdsSelfLocked.keyAt(i));
-                        pw.print(" -> profile #");
-                        pw.println(mUserProfileGroupIdsSelfLocked.valueAt(i));
-                    }
-                }
-            }
+            mUserController.dump(pw, dumpAll);
         }
         if (mHomeProcess != null && (dumpPackage == null
                 || mHomeProcess.pkgList.containsKey(dumpPackage))) {
@@ -16098,9 +16035,9 @@
                 requireFull ? ALLOW_FULL_ONLY : ALLOW_NON_FULL, name, callerPackage);
     }
 
-    int unsafeConvertIncomingUser(int userId) {
+    int unsafeConvertIncomingUserLocked(int userId) {
         return (userId == UserHandle.USER_CURRENT || userId == UserHandle.USER_CURRENT_OR_SELF)
-                ? mCurrentUserId : userId;
+                ? mUserController.mCurrentUserId : userId;
     }
 
     int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
@@ -16116,7 +16053,7 @@
         // the value the caller will receive and someone else changing it.
         // We assume that USER_CURRENT_OR_SELF will use the current user; later
         // we will switch to the calling user if access to the current user fails.
-        int targetUserId = unsafeConvertIncomingUser(userId);
+        int targetUserId = unsafeConvertIncomingUserLocked(userId);
 
         if (callingUid != 0 && callingUid != Process.SYSTEM_UID) {
             final boolean allow;
@@ -16137,14 +16074,7 @@
             } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
                 // We may or may not allow this depending on whether the two users are
                 // in the same profile.
-                synchronized (mUserProfileGroupIdsSelfLocked) {
-                    int callingProfile = mUserProfileGroupIdsSelfLocked.get(callingUserId,
-                            UserInfo.NO_PROFILE_GROUP_ID);
-                    int targetProfile = mUserProfileGroupIdsSelfLocked.get(targetUserId,
-                            UserInfo.NO_PROFILE_GROUP_ID);
-                    allow = callingProfile != UserInfo.NO_PROFILE_GROUP_ID
-                            && callingProfile == targetProfile;
-                }
+                allow = mUserController.isSameProfileGroup(callingUserId, targetUserId);
             } else {
                 throw new IllegalArgumentException("Unknown mode: " + allowMode);
             }
@@ -16763,7 +16693,7 @@
         return receivers;
     }
 
-    private final int broadcastIntentLocked(ProcessRecord callerApp,
+    final int broadcastIntentLocked(ProcessRecord callerApp,
             String callerPackage, Intent intent, String resolvedType,
             IIntentReceiver resultTo, int resultCode, String resultData,
             Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options,
@@ -17080,7 +17010,7 @@
         int[] users;
         if (userId == UserHandle.USER_ALL) {
             // Caller wants broadcast to go to all started users.
-            users = mStartedUserArray;
+            users = mUserController.getStartedUserArrayLocked();
         } else {
             // Caller wants broadcast to go to one specific user.
             users = new int[] {userId};
@@ -17667,6 +17597,12 @@
             Binder.restoreCallingIdentity(origId);
         }
     }
+    void updateUserConfigurationLocked() {
+        Configuration configuration = new Configuration(mConfiguration);
+        Settings.System.getConfigurationForUser(mContext.getContentResolver(), configuration,
+                mUserController.mCurrentUserId);
+        updateConfigurationLocked(configuration, null, false);
+    }
 
     boolean updateConfigurationLocked(Configuration values,
             ActivityRecord starting, boolean initLocale) {
@@ -17712,7 +17648,8 @@
                 newConfig.seq = mConfigurationSeq;
                 mConfiguration = newConfig;
                 Slog.i(TAG, "Config changes=" + Integer.toHexString(changes) + " " + newConfig);
-                mUsageStatsService.reportConfigurationChange(newConfig, mCurrentUserId);
+                mUsageStatsService.reportConfigurationChange(newConfig,
+                        mUserController.mCurrentUserId);
                 //mUsageStatsService.noteStartConfig(newConfig);
 
                 final Configuration configCopy = new Configuration(mConfiguration);
@@ -19196,7 +19133,7 @@
             String authority) {
         if (app == null) return;
         if (app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-            UserState userState = mStartedUsers.get(app.userId);
+            UserState userState = mUserController.getStartedUserState(app.userId);
             if (userState == null) return;
             final long now = SystemClock.elapsedRealtime();
             Long lastReported = userState.mProviderLastReportedFg.get(authority);
@@ -20076,44 +20013,18 @@
      */
     @Override
     public boolean startUserInBackground(final int userId) {
-        return startUser(userId, /* foreground */ false);
+        return mUserController.startUser(userId, /* foreground */ false);
     }
 
     /**
      * Start user, if its not already running, and bring it to foreground.
      */
     boolean startUserInForeground(final int userId, Dialog dlg) {
-        boolean result = startUser(userId, /* foreground */ true);
+        boolean result = mUserController.startUser(userId, /* foreground */ true);
         dlg.dismiss();
         return result;
     }
 
-    /**
-     * Refreshes the list of users related to the current user when either a
-     * user switch happens or when a new related user is started in the
-     * background.
-     */
-    private void updateCurrentProfileIdsLocked() {
-        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
-                mCurrentUserId, false /* enabledOnly */);
-        int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
-        for (int i = 0; i < currentProfileIds.length; i++) {
-            currentProfileIds[i] = profiles.get(i).id;
-        }
-        mCurrentProfileIds = currentProfileIds;
-
-        synchronized (mUserProfileGroupIdsSelfLocked) {
-            mUserProfileGroupIdsSelfLocked.clear();
-            final List<UserInfo> users = getUserManagerLocked().getUsers(false);
-            for (int i = 0; i < users.size(); i++) {
-                UserInfo user = users.get(i);
-                if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
-                    mUserProfileGroupIdsSelfLocked.put(user.id, user.profileGroupId);
-                }
-            }
-        }
-    }
-
     private Set<Integer> getProfileIdsLocked(int userId) {
         Set<Integer> userIds = new HashSet<Integer>();
         final List<UserInfo> profiles = getUserManagerLocked().getProfiles(
@@ -20139,7 +20050,7 @@
                 return false;
             }
             userName = userInfo.name;
-            mTargetUserId = userId;
+            mUserController.mTargetUserId = userId;
         }
         mUiHandler.removeMessages(START_USER_SWITCH_MSG);
         mUiHandler.sendMessage(mUiHandler.obtainMessage(START_USER_SWITCH_MSG, userId, 0, userName));
@@ -20153,186 +20064,6 @@
         d.show();
     }
 
-    private boolean startUser(final int userId, final boolean foreground) {
-        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED) {
-            String msg = "Permission Denial: switchUser() from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid()
-                    + " requires " + INTERACT_ACROSS_USERS_FULL;
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-
-        if (DEBUG_MU) Slog.i(TAG_MU, "starting userid:" + userId + " fore:" + foreground);
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            synchronized (this) {
-                final int oldUserId = mCurrentUserId;
-                if (oldUserId == userId) {
-                    return true;
-                }
-
-                mStackSupervisor.setLockTaskModeLocked(null, ActivityManager.LOCK_TASK_MODE_NONE,
-                        "startUser", false);
-
-                final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
-                if (userInfo == null) {
-                    Slog.w(TAG, "No user info for user #" + userId);
-                    return false;
-                }
-                if (foreground && userInfo.isManagedProfile()) {
-                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
-                    return false;
-                }
-
-                if (foreground) {
-                    mWindowManager.startFreezingScreen(R.anim.screen_user_exit,
-                            R.anim.screen_user_enter);
-                }
-
-                boolean needStart = false;
-
-                // If the user we are switching to is not currently started, then
-                // we need to start it now.
-                if (mStartedUsers.get(userId) == null) {
-                    mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
-                    updateStartedUserArrayLocked();
-                    needStart = true;
-                }
-
-                final Integer userIdInt = Integer.valueOf(userId);
-                mUserLru.remove(userIdInt);
-                mUserLru.add(userIdInt);
-
-                if (foreground) {
-                    mCurrentUserId = userId;
-                    updateUserConfigurationLocked();
-                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
-                    updateCurrentProfileIdsLocked();
-                    mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
-                    // Once the internal notion of the active user has switched, we lock the device
-                    // with the option to show the user switcher on the keyguard.
-                    mWindowManager.lockNow(null);
-                } else {
-                    final Integer currentUserIdInt = Integer.valueOf(mCurrentUserId);
-                    updateCurrentProfileIdsLocked();
-                    mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
-                    mUserLru.remove(currentUserIdInt);
-                    mUserLru.add(currentUserIdInt);
-                }
-
-                final UserState uss = mStartedUsers.get(userId);
-
-                // Make sure user is in the started state.  If it is currently
-                // stopping, we need to knock that off.
-                if (uss.mState == UserState.STATE_STOPPING) {
-                    // If we are stopping, we haven't sent ACTION_SHUTDOWN,
-                    // so we can just fairly silently bring the user back from
-                    // the almost-dead.
-                    uss.mState = UserState.STATE_RUNNING;
-                    updateStartedUserArrayLocked();
-                    needStart = true;
-                } else if (uss.mState == UserState.STATE_SHUTDOWN) {
-                    // This means ACTION_SHUTDOWN has been sent, so we will
-                    // need to treat this as a new boot of the user.
-                    uss.mState = UserState.STATE_BOOTING;
-                    updateStartedUserArrayLocked();
-                    needStart = true;
-                }
-
-                if (uss.mState == UserState.STATE_BOOTING) {
-                    // Booting up a new user, need to tell system services about it.
-                    // Note that this is on the same handler as scheduling of broadcasts,
-                    // which is important because it needs to go first.
-                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
-                }
-
-                if (foreground) {
-                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
-                            oldUserId));
-                    mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
-                    mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
-                    mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
-                            oldUserId, userId, uss));
-                    mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
-                            oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
-                }
-
-                if (needStart) {
-                    // Send USER_STARTED broadcast
-                    Intent intent = new Intent(Intent.ACTION_USER_STARTED);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
-                            | Intent.FLAG_RECEIVER_FOREGROUND);
-                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                    broadcastIntentLocked(null, null, intent,
-                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
-                            null, false, false, MY_PID, Process.SYSTEM_UID, userId);
-                }
-
-                if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
-                    if (userId != UserHandle.USER_SYSTEM) {
-                        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
-                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                        broadcastIntentLocked(null, null, intent, null,
-                                new IIntentReceiver.Stub() {
-                                    public void performReceive(Intent intent, int resultCode,
-                                            String data, Bundle extras, boolean ordered,
-                                            boolean sticky, int sendingUser) {
-                                        onUserInitialized(uss, foreground, oldUserId, userId);
-                                    }
-                                }, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, MY_PID, Process.SYSTEM_UID, userId);
-                        uss.initializing = true;
-                    } else {
-                        getUserManagerLocked().makeInitialized(userInfo.id);
-                    }
-                }
-
-                if (foreground) {
-                    if (!uss.initializing) {
-                        moveUserToForegroundLocked(uss, oldUserId, userId);
-                    }
-                } else {
-                    mStackSupervisor.startBackgroundUserLocked(userId, uss);
-                }
-
-                if (needStart) {
-                    Intent intent = new Intent(Intent.ACTION_USER_STARTING);
-                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                    broadcastIntentLocked(null, null, intent,
-                            null, new IIntentReceiver.Stub() {
-                                @Override
-                                public void performReceive(Intent intent, int resultCode,
-                                        String data, Bundle extras, boolean ordered, boolean sticky,
-                                        int sendingUser) throws RemoteException {
-                                }
-                            }, 0, null, null,
-                            new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                            null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        return true;
-    }
-
-    void dispatchForegroundProfileChanged(int userId) {
-        final int N = mUserSwitchObservers.beginBroadcast();
-        for (int i = 0; i < N; i++) {
-            try {
-                mUserSwitchObservers.getBroadcastItem(i).onForegroundProfileSwitch(userId);
-            } catch (RemoteException e) {
-                // Ignore
-            }
-        }
-        mUserSwitchObservers.finishBroadcast();
-    }
-
     void sendUserSwitchBroadcastsLocked(int oldUserId, int newUserId) {
         long ident = Binder.clearCallingIdentity();
         try {
@@ -20381,150 +20112,6 @@
         }
     }
 
-    void dispatchUserSwitch(final UserState uss, final int oldUserId,
-            final int newUserId) {
-        final int N = mUserSwitchObservers.beginBroadcast();
-        if (N > 0) {
-            final IRemoteCallback callback = new IRemoteCallback.Stub() {
-                int mCount = 0;
-                @Override
-                public void sendResult(Bundle data) throws RemoteException {
-                    synchronized (ActivityManagerService.this) {
-                        if (mCurUserSwitchCallback == this) {
-                            mCount++;
-                            if (mCount == N) {
-                                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
-                            }
-                        }
-                    }
-                }
-            };
-            synchronized (this) {
-                uss.switching = true;
-                mCurUserSwitchCallback = callback;
-            }
-            for (int i=0; i<N; i++) {
-                try {
-                    mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
-                            newUserId, callback);
-                } catch (RemoteException e) {
-                }
-            }
-        } else {
-            synchronized (this) {
-                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
-            }
-        }
-        mUserSwitchObservers.finishBroadcast();
-    }
-
-    void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
-        synchronized (this) {
-            Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
-            sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
-        }
-    }
-
-    void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
-        mCurUserSwitchCallback = null;
-        mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
-        mHandler.sendMessage(mHandler.obtainMessage(CONTINUE_USER_SWITCH_MSG,
-                oldUserId, newUserId, uss));
-    }
-
-    void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
-        synchronized (this) {
-            if (foreground) {
-                moveUserToForegroundLocked(uss, oldUserId, newUserId);
-            }
-        }
-
-        completeSwitchAndInitialize(uss, newUserId, true, false);
-    }
-
-    void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
-        boolean homeInFront = mStackSupervisor.switchUserLocked(newUserId, uss);
-        if (homeInFront) {
-            startHomeActivityLocked(newUserId, "moveUserToFroreground");
-        } else {
-            mStackSupervisor.resumeTopActivitiesLocked();
-        }
-        EventLogTags.writeAmSwitchUser(newUserId);
-        getUserManagerLocked().onUserForeground(newUserId);
-        sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
-    }
-
-    private void updateUserConfigurationLocked() {
-        Configuration configuration = new Configuration(mConfiguration);
-        Settings.System.getConfigurationForUser(mContext.getContentResolver(), configuration,
-                mCurrentUserId);
-        updateConfigurationLocked(configuration, null, false);
-    }
-
-    void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
-        completeSwitchAndInitialize(uss, newUserId, false, true);
-    }
-
-    void completeSwitchAndInitialize(UserState uss, int newUserId,
-            boolean clearInitializing, boolean clearSwitching) {
-        boolean unfrozen = false;
-        synchronized (this) {
-            if (clearInitializing) {
-                uss.initializing = false;
-                getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
-            }
-            if (clearSwitching) {
-                uss.switching = false;
-            }
-            if (!uss.switching && !uss.initializing) {
-                mWindowManager.stopFreezingScreen();
-                unfrozen = true;
-            }
-        }
-        if (unfrozen) {
-            mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
-            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
-                    newUserId, 0));
-        }
-        stopGuestUserIfBackground();
-    }
-
-    /** Called on handler thread */
-    void dispatchUserSwitchComplete(int userId) {
-        final int observerCount = mUserSwitchObservers.beginBroadcast();
-        for (int i = 0; i < observerCount; i++) {
-            try {
-                mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId);
-            } catch (RemoteException e) {
-            }
-        }
-        mUserSwitchObservers.finishBroadcast();
-    }
-
-    /**
-     * Stops the guest user if it has gone to the background.
-     */
-    private void stopGuestUserIfBackground() {
-        synchronized (this) {
-            final int num = mUserLru.size();
-            for (int i = 0; i < num; i++) {
-                Integer oldUserId = mUserLru.get(i);
-                UserState oldUss = mStartedUsers.get(oldUserId);
-                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
-                        || oldUss.mState == UserState.STATE_STOPPING
-                        || oldUss.mState == UserState.STATE_SHUTDOWN) {
-                    continue;
-                }
-                UserInfo userInfo = mUserManager.getUserInfo(oldUserId);
-                if (userInfo.isGuest()) {
-                    // This is a user to be stopped.
-                    stopUserLocked(oldUserId, null);
-                    break;
-                }
-            }
-        }
-    }
-
     void scheduleStartProfilesLocked() {
         if (!mHandler.hasMessages(START_PROFILES_MSG)) {
             mHandler.sendMessageDelayed(mHandler.obtainMessage(START_PROFILES_MSG),
@@ -20532,229 +20119,9 @@
         }
     }
 
-    void startProfilesLocked() {
-        if (DEBUG_MU) Slog.i(TAG_MU, "startProfilesLocked");
-        List<UserInfo> profiles = getUserManagerLocked().getProfiles(
-                mCurrentUserId, false /* enabledOnly */);
-        List<UserInfo> toStart = new ArrayList<UserInfo>(profiles.size());
-        for (UserInfo user : profiles) {
-            if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
-                    && user.id != mCurrentUserId) {
-                toStart.add(user);
-            }
-        }
-        final int n = toStart.size();
-        int i = 0;
-        for (; i < n && i < (MAX_RUNNING_USERS - 1); ++i) {
-            startUserInBackground(toStart.get(i).id);
-        }
-        if (i < n) {
-            Slog.w(TAG_MU, "More profiles than MAX_RUNNING_USERS");
-        }
-    }
-
-    void finishUserBoot(UserState uss) {
-        synchronized (this) {
-            if (uss.mState == UserState.STATE_BOOTING
-                    && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
-                uss.mState = UserState.STATE_RUNNING;
-                final int userId = uss.mHandle.getIdentifier();
-                Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
-                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
-                broadcastIntentLocked(null, null, intent,
-                        null, null, 0, null, null,
-                        new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
-                        AppOpsManager.OP_NONE, null, true, false, MY_PID, Process.SYSTEM_UID,
-                        userId);
-            }
-        }
-    }
-
-    void finishUserSwitch(UserState uss) {
-        synchronized (this) {
-            finishUserBoot(uss);
-
-            startProfilesLocked();
-
-            int num = mUserLru.size();
-            int i = 0;
-            while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
-                Integer oldUserId = mUserLru.get(i);
-                UserState oldUss = mStartedUsers.get(oldUserId);
-                if (oldUss == null) {
-                    // Shouldn't happen, but be sane if it does.
-                    mUserLru.remove(i);
-                    num--;
-                    continue;
-                }
-                if (oldUss.mState == UserState.STATE_STOPPING
-                        || oldUss.mState == UserState.STATE_SHUTDOWN) {
-                    // This user is already stopping, doesn't count.
-                    num--;
-                    i++;
-                    continue;
-                }
-                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
-                    // Owner/System user and current user can't be stopped. We count it as running
-                    // when it is not a pure system user.
-                    if (UserInfo.isSystemOnly(oldUserId)) {
-                        num--;
-                    }
-                    i++;
-                    continue;
-                }
-                // This is a user to be stopped.
-                stopUserLocked(oldUserId, null);
-                num--;
-                i++;
-            }
-        }
-    }
-
     @Override
     public int stopUser(final int userId, final IStopUserCallback callback) {
-        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED) {
-            String msg = "Permission Denial: switchUser() from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid()
-                    + " requires " + INTERACT_ACROSS_USERS_FULL;
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-        if (userId < 0 || userId == UserHandle.USER_SYSTEM) {
-            throw new IllegalArgumentException("Can't stop system user " + userId);
-        }
-        enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
-        synchronized (this) {
-            return stopUserLocked(userId, callback);
-        }
-    }
-
-    private int stopUserLocked(final int userId, final IStopUserCallback callback) {
-        if (DEBUG_MU) Slog.i(TAG_MU, "stopUserLocked userId=" + userId);
-        if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {
-            return ActivityManager.USER_OP_IS_CURRENT;
-        }
-
-        final UserState uss = mStartedUsers.get(userId);
-        if (uss == null) {
-            // User is not started, nothing to do...  but we do need to
-            // callback if requested.
-            if (callback != null) {
-                mHandler.post(new Runnable() {
-                    @Override
-                    public void run() {
-                        try {
-                            callback.userStopped(userId);
-                        } catch (RemoteException e) {
-                        }
-                    }
-                });
-            }
-            return ActivityManager.USER_OP_SUCCESS;
-        }
-
-        if (callback != null) {
-            uss.mStopCallbacks.add(callback);
-        }
-
-        if (uss.mState != UserState.STATE_STOPPING
-                && uss.mState != UserState.STATE_SHUTDOWN) {
-            uss.mState = UserState.STATE_STOPPING;
-            updateStartedUserArrayLocked();
-
-            long ident = Binder.clearCallingIdentity();
-            try {
-                // We are going to broadcast ACTION_USER_STOPPING and then
-                // once that is done send a final ACTION_SHUTDOWN and then
-                // stop the user.
-                final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
-                stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-                stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
-                final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
-                // This is the result receiver for the final shutdown broadcast.
-                final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
-                    @Override
-                    public void performReceive(Intent intent, int resultCode, String data,
-                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        finishUserStop(uss);
-                    }
-                };
-                // This is the result receiver for the initial stopping broadcast.
-                final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
-                    @Override
-                    public void performReceive(Intent intent, int resultCode, String data,
-                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-                        // On to the next.
-                        synchronized (ActivityManagerService.this) {
-                            if (uss.mState != UserState.STATE_STOPPING) {
-                                // Whoops, we are being started back up.  Abort, abort!
-                                return;
-                            }
-                            uss.mState = UserState.STATE_SHUTDOWN;
-                        }
-                        mBatteryStatsService.noteEvent(
-                                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
-                                Integer.toString(userId), userId);
-                        mSystemServiceManager.stopUser(userId);
-                        broadcastIntentLocked(null, null, shutdownIntent,
-                                null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, MY_PID, Process.SYSTEM_UID, userId);
-                    }
-                };
-                // Kick things off.
-                broadcastIntentLocked(null, null, stoppingIntent,
-                        null, stoppingReceiver, 0, null, null,
-                        new String[] {INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
-                        null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
-
-        return ActivityManager.USER_OP_SUCCESS;
-    }
-
-    void finishUserStop(UserState uss) {
-        final int userId = uss.mHandle.getIdentifier();
-        boolean stopped;
-        ArrayList<IStopUserCallback> callbacks;
-        synchronized (this) {
-            callbacks = new ArrayList<IStopUserCallback>(uss.mStopCallbacks);
-            if (mStartedUsers.get(userId) != uss) {
-                stopped = false;
-            } else if (uss.mState != UserState.STATE_SHUTDOWN) {
-                stopped = false;
-            } else {
-                stopped = true;
-                // User can no longer run.
-                mStartedUsers.remove(userId);
-                mUserLru.remove(Integer.valueOf(userId));
-                updateStartedUserArrayLocked();
-
-                // Clean up all state and processes associated with the user.
-                // Kill all the processes for the user.
-                forceStopUserLocked(userId, "finish user");
-            }
-        }
-
-        for (int i=0; i<callbacks.size(); i++) {
-            try {
-                if (stopped) callbacks.get(i).userStopped(userId);
-                else callbacks.get(i).userStopAborted(userId);
-            } catch (RemoteException e) {
-            }
-        }
-
-        if (stopped) {
-            mSystemServiceManager.cleanupUser(userId);
-            synchronized (this) {
-                mStackSupervisor.removeUserLocked(userId);
-            }
-        }
+        return mUserController.stopUser(userId, callback);
     }
 
     void onUserRemovedLocked(int userId) {
@@ -20763,25 +20130,7 @@
 
     @Override
     public UserInfo getCurrentUser() {
-        if ((checkCallingPermission(INTERACT_ACROSS_USERS)
-                != PackageManager.PERMISSION_GRANTED) && (
-                checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED)) {
-            String msg = "Permission Denial: getCurrentUser() from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid()
-                    + " requires " + INTERACT_ACROSS_USERS;
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-        synchronized (this) {
-            int userId = mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
-            return getUserManagerLocked().getUserInfo(userId);
-        }
-    }
-
-    int getCurrentUserIdLocked() {
-        return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
+        return mUserController.getCurrentUser();
     }
 
     @Override
@@ -20801,7 +20150,7 @@
     }
 
     boolean isUserRunningLocked(int userId, boolean orStopped) {
-        UserState state = mStartedUsers.get(userId);
+        UserState state = mUserController.getStartedUserState(userId);
         if (state == null) {
             return false;
         }
@@ -20824,50 +20173,18 @@
             throw new SecurityException(msg);
         }
         synchronized (this) {
-            return mStartedUserArray;
-        }
-    }
-
-    private void updateStartedUserArrayLocked() {
-        int num = 0;
-        for (int i=0; i<mStartedUsers.size();  i++) {
-            UserState uss = mStartedUsers.valueAt(i);
-            // This list does not include stopping users.
-            if (uss.mState != UserState.STATE_STOPPING
-                    && uss.mState != UserState.STATE_SHUTDOWN) {
-                num++;
-            }
-        }
-        mStartedUserArray = new int[num];
-        num = 0;
-        for (int i=0; i<mStartedUsers.size();  i++) {
-            UserState uss = mStartedUsers.valueAt(i);
-            if (uss.mState != UserState.STATE_STOPPING
-                    && uss.mState != UserState.STATE_SHUTDOWN) {
-                mStartedUserArray[num] = mStartedUsers.keyAt(i);
-                num++;
-            }
+            return mUserController.getStartedUserArrayLocked();
         }
     }
 
     @Override
     public void registerUserSwitchObserver(IUserSwitchObserver observer) {
-        if (checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
-                != PackageManager.PERMISSION_GRANTED) {
-            String msg = "Permission Denial: registerUserSwitchObserver() from pid="
-                    + Binder.getCallingPid()
-                    + ", uid=" + Binder.getCallingUid()
-                    + " requires " + INTERACT_ACROSS_USERS_FULL;
-            Slog.w(TAG, msg);
-            throw new SecurityException(msg);
-        }
-
-        mUserSwitchObservers.register(observer);
+        mUserController.registerUserSwitchObserver(observer);
     }
 
     @Override
     public void unregisterUserSwitchObserver(IUserSwitchObserver observer) {
-        mUserSwitchObservers.unregister(observer);
+        mUserController.unregisterUserSwitchObserver(observer);
     }
 
     int[] getUsersLocked() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
new file mode 100644
index 0000000..d1e7e85
--- /dev/null
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.app.IActivityManager;
+import android.os.RemoteException;
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+class ActivityManagerShellCommand extends ShellCommand {
+    // IPC interface to activity manager -- don't need to do additional security checks.
+    final IActivityManager mInterface;
+
+    // Internal service impl -- must perform security checks before touching.
+    final ActivityManagerService mInternal;
+
+    final boolean mDumping;
+
+    ActivityManagerShellCommand(ActivityManagerService service, boolean dumping) {
+        mInterface = service;
+        mInternal = service;
+        mDumping = dumping;
+    }
+
+    @Override
+    public int onCommand(String cmd) {
+        if (cmd == null) {
+            return handleDefaultCommands(cmd);
+        }
+        PrintWriter pw = getOutPrintWriter();
+        try {
+            switch (cmd) {
+                case "force-stop":
+                    return runForceStop(pw);
+                case "kill":
+                    return runKill(pw);
+                case "kill-all":
+                    return runKillAll(pw);
+                case "write":
+                    return runWrite(pw);
+                case "track-associations":
+                    return runTrackAssociations(pw);
+                case "untrack-associations":
+                    return runUntrackAssociations(pw);
+                default:
+                    return handleDefaultCommands(cmd);
+            }
+        } catch (RemoteException e) {
+            pw.println("Remote exception: " + e);
+        }
+        return -1;
+    }
+
+    int runForceStop(PrintWriter pw) throws RemoteException {
+        int userId = UserHandle.USER_ALL;
+
+        String opt;
+        while ((opt = getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = parseUserArg(getNextArgRequired());
+            } else {
+                pw.println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+        mInterface.forceStopPackage(getNextArgRequired(), userId);
+        return 0;
+    }
+
+    int runKill(PrintWriter pw) throws RemoteException {
+        int userId = UserHandle.USER_ALL;
+
+        String opt;
+        while ((opt=getNextOption()) != null) {
+            if (opt.equals("--user")) {
+                userId = parseUserArg(getNextArgRequired());
+            } else {
+                pw.println("Error: Unknown option: " + opt);
+                return -1;
+            }
+        }
+        mInterface.killBackgroundProcesses(getNextArgRequired(), userId);
+        return 0;
+    }
+
+    int runKillAll(PrintWriter pw) throws RemoteException {
+        mInterface.killAllBackgroundProcesses();
+        return 0;
+    }
+
+    int runWrite(PrintWriter pw) {
+        mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "registerUidObserver()");
+        mInternal.mTaskPersister.flush();
+        pw.println("All tasks persisted.");
+        return 0;
+    }
+
+    int runTrackAssociations(PrintWriter pw) {
+        mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "registerUidObserver()");
+        synchronized (mInternal) {
+            if (!mInternal.mTrackingAssociations) {
+                mInternal.mTrackingAssociations = true;
+                pw.println("Association tracking started.");
+            } else {
+                pw.println("Association tracking already enabled.");
+            }
+        }
+        return 0;
+    }
+
+    int runUntrackAssociations(PrintWriter pw) {
+        mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+                "registerUidObserver()");
+        synchronized (mInternal) {
+            if (mInternal.mTrackingAssociations) {
+                mInternal.mTrackingAssociations = false;
+                mInternal.mAssociations.clear();
+                pw.println("Association tracking stopped.");
+            } else {
+                pw.println("Association tracking not running.");
+            }
+        }
+        return 0;
+    }
+
+    int parseUserArg(String arg) {
+        int userId;
+        if ("all".equals(arg)) {
+            userId = UserHandle.USER_ALL;
+        } else if ("current".equals(arg) || "cur".equals(arg)) {
+            userId = UserHandle.USER_CURRENT;
+        } else {
+            try {
+                userId = Integer.parseInt(arg);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Bad user number: " + arg);
+            }
+        }
+        return userId;
+    }
+
+    @Override
+    public void onHelp() {
+        PrintWriter pw = getOutPrintWriter();
+        dumpHelp(pw, mDumping);
+    }
+
+    static void dumpHelp(PrintWriter pw, boolean dumping) {
+        if (dumping) {
+            pw.println("Activity manager dump options:");
+            pw.println("  [-a] [-c] [-p PACKAGE] [-h] [WHAT] ...");
+            pw.println("  WHAT may be one of:");
+            pw.println("    a[ctivities]: activity stack state");
+            pw.println("    r[recents]: recent activities state");
+            pw.println("    b[roadcasts] [PACKAGE_NAME] [history [-s]]: broadcast state");
+            pw.println("    i[ntents] [PACKAGE_NAME]: pending intent state");
+            pw.println("    p[rocesses] [PACKAGE_NAME]: process state");
+            pw.println("    o[om]: out of memory management");
+            pw.println("    perm[issions]: URI permission grant state");
+            pw.println("    prov[iders] [COMP_SPEC ...]: content provider state");
+            pw.println("    provider [COMP_SPEC]: provider client-side state");
+            pw.println("    s[ervices] [COMP_SPEC ...]: service state");
+            pw.println("    as[sociations]: tracked app associations");
+            pw.println("    service [COMP_SPEC]: service client-side state");
+            pw.println("    package [PACKAGE_NAME]: all state related to given package");
+            pw.println("    all: dump all activities");
+            pw.println("    top: dump the top activity");
+            pw.println("  WHAT may also be a COMP_SPEC to dump activities.");
+            pw.println("  COMP_SPEC may be a component name (com.foo/.myApp),");
+            pw.println("    a partial substring in a component name, a");
+            pw.println("    hex object identifier.");
+            pw.println("  -a: include all available server state.");
+            pw.println("  -c: include client state.");
+            pw.println("  -p: limit output to given package.");
+        } else {
+            pw.println("Activity manager (activity) commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println("  force-stop [--user <USER_ID> | all | current] <PACKAGE>");
+            pw.println("    Complete stop the given application package.");
+            pw.println("  kill [--user <USER_ID> | all | current] <PACKAGE>");
+            pw.println("    Kill all processes associated with the given application.");
+            pw.println("  kill-all");
+            pw.println("    Kill all processes that are safe to kill (cached, etc)");
+            pw.println("  write");
+            pw.println("    Write all pending state to storage.");
+            pw.println("  track-associations");
+            pw.println("    Enable association tracking.");
+            pw.println("  untrack-associations");
+            pw.println("    Disable and clear association tracking.");
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4671cb0..76c4f1e 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -53,6 +53,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.TimeUtils;
+import android.view.AppTransitionAnimationSpec;
 import android.view.IApplicationToken;
 import android.view.WindowManager;
 
@@ -189,6 +190,7 @@
     // and drawable-sw400dp will be added to both as 400.
     private int[] mVerticalSizeConfigurations;
     private int[] mHorizontalSizeConfigurations;
+    private int[] mSmallestSizeConfigurations;
 
     void dump(PrintWriter pw, String prefix) {
         final long now = SystemClock.uptimeMillis();
@@ -341,6 +343,10 @@
         return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp);
     }
 
+    public boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
+        return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp);
+    }
+
     /**
      * The purpose of this method is to decide whether the activity needs to be relaunched upon
      * changing its size. In most cases the activities don't need to be relaunched, if the resize
@@ -371,9 +377,10 @@
     }
 
     public void setSizeConfigurations(int[] horizontalSizeConfiguration,
-            int[] verticalSizeConfigurations) {
+            int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
         mHorizontalSizeConfigurations = horizontalSizeConfiguration;
         mVerticalSizeConfigurations = verticalSizeConfigurations;
+        mSmallestSizeConfigurations = smallestSizeConfigurations;
     }
 
     static class Token extends IApplicationToken.Stub {
@@ -863,17 +870,25 @@
                     break;
                 case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP:
                 case ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
-                    service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
-                            pendingOptions.getThumbnail(),
-                            pendingOptions.getStartX(), pendingOptions.getStartY(),
-                            pendingOptions.getWidth(), pendingOptions.getHeight(),
-                            pendingOptions.getOnAnimationStartListener(),
-                            (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP));
-                    if (intent.getSourceBounds() == null) {
-                        intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
-                                pendingOptions.getStartY(),
-                                pendingOptions.getStartX() + pendingOptions.getWidth(),
-                                pendingOptions.getStartY() + pendingOptions.getHeight()));
+                    final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
+                    if (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
+                            && specs != null) {
+                        service.mWindowManager.overridePendingAppTransitionMultiThumb(
+                                specs, pendingOptions.getOnAnimationStartListener(),
+                                pendingOptions.getAnimationFinishedListener(), false);
+                    } else {
+                        service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
+                                pendingOptions.getThumbnail(),
+                                pendingOptions.getStartX(), pendingOptions.getStartY(),
+                                pendingOptions.getWidth(), pendingOptions.getHeight(),
+                                pendingOptions.getOnAnimationStartListener(),
+                                (animationType == ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP));
+                        if (intent.getSourceBounds() == null) {
+                            intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
+                                    pendingOptions.getStartY(),
+                                    pendingOptions.getStartX() + pendingOptions.getWidth(),
+                                    pendingOptions.getStartY() + pendingOptions.getHeight()));
+                        }
                     }
                     break;
                 default:
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1721470..b5f424d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -21,7 +21,9 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.INVALID_STACK_ID;
 import static android.app.ActivityManager.LAST_STATIC_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
@@ -253,6 +255,9 @@
 
     private final LaunchingTaskPositioner mTaskPositioner;
 
+    // If the bounds of task contained in this stack should be persisted across power cycles.
+    final boolean mPersistTaskBounds;
+
     static final int PAUSE_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 1;
     static final int DESTROY_TIMEOUT_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 2;
     static final int LAUNCH_TICK_MSG = ActivityManagerService.FIRST_ACTIVITY_STACK_MSG + 3;
@@ -354,10 +359,6 @@
         return count;
     }
 
-    int numTasks() {
-        return mTaskHistory.size();
-    }
-
     ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
             RecentTasks recentTasks) {
         mActivityContainer = activityContainer;
@@ -366,10 +367,11 @@
         mHandler = new ActivityStackHandler(mService.mHandler.getLooper());
         mWindowManager = mService.mWindowManager;
         mStackId = activityContainer.mStackId;
-        mCurrentUser = mService.mCurrentUserId;
+        mCurrentUser = mService.mUserController.mCurrentUserId;
         mRecentTasks = recentTasks;
         mTaskPositioner = mStackId == FREEFORM_WORKSPACE_STACK_ID
                 ? new LaunchingTaskPositioner() : null;
+        mPersistTaskBounds = mStackId != DOCKED_STACK_ID && mStackId != PINNED_STACK_ID;
     }
 
     void attachDisplay(ActivityStackSupervisor.ActivityDisplay activityDisplay, boolean onTop) {
@@ -528,25 +530,35 @@
      * @param task If non-null, the task will be moved to the top of the stack.
      * */
     void moveToFront(String reason, TaskRecord task) {
-        if (isAttached()) {
-            final ActivityStack lastFocusStack = mStacks.get(mStacks.size() - 1);
-            // Need to move this stack to the front before calling
-            // {@link ActivityStackSupervisor#setFocusStack} below.
-            mStacks.remove(this);
-            mStacks.add(this);
+        if (!isAttached()) {
+            return;
+        }
 
-            // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
-            if (isOnHomeDisplay()) {
-                mStackSupervisor.setFocusStack(reason, lastFocusStack);
+        mStacks.remove(this);
+        int addIndex = mStacks.size();
+
+        if (addIndex > 0) {
+            final ActivityStack topStack = mStacks.get(addIndex - 1);
+            if (topStack.mStackId == PINNED_STACK_ID && topStack != this) {
+                // The pinned stack is always the top most stack (always-on-top).
+                // So, stack is moved just below the pinned stack.
+                addIndex--;
             }
-            if (task != null) {
-                insertTaskAtTop(task, null);
-            } else {
-                task = topTask();
-            }
-            if (task != null) {
-                mWindowManager.moveTaskToTop(task.taskId);
-            }
+        }
+
+        mStacks.add(addIndex, this);
+
+        // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
+        if (isOnHomeDisplay()) {
+            mStackSupervisor.setFocusStack(reason, this);
+        }
+        if (task != null) {
+            insertTaskAtTop(task, null);
+        } else {
+            task = topTask();
+        }
+        if (task != null) {
+            mWindowManager.moveTaskToTop(task.taskId);
         }
     }
 
@@ -1302,7 +1314,7 @@
             return false;
         }
 
-        if (mStackSupervisor.isFrontStack(this)) {
+        if (mStackSupervisor.isFrontStack(this) || mStackSupervisor.isFocusedStack(this)) {
             return true;
         }
 
@@ -1328,8 +1340,9 @@
         }
 
         final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
-        if (focusedStackId == DOCKED_STACK_ID && stackIndex == belowFocusedIndex) {
-            // Stacks directly behind the docked stack are always visible.
+        if ((focusedStackId == DOCKED_STACK_ID || focusedStackId == PINNED_STACK_ID)
+                && stackIndex == belowFocusedIndex) {
+            // Stacks directly behind the docked or pinned stack are always visible.
             return true;
         }
 
@@ -1343,9 +1356,10 @@
             }
             if (belowFocusedIndex >= 0) {
                 final ActivityStack stack = mStacks.get(belowFocusedIndex);
-                if (stack.mStackId == DOCKED_STACK_ID && stackIndex == (belowFocusedIndex - 1)) {
-                    // The stack behind the docked stack is also visible so we can have a complete
-                    // backdrop to the translucent activity when the docked stack is up.
+                if ((stack.mStackId == DOCKED_STACK_ID || stack.mStackId == PINNED_STACK_ID)
+                        && stackIndex == (belowFocusedIndex - 1)) {
+                    // The stack behind the docked or pinned stack is also visible so we can have a
+                    // complete backdrop to the translucent activity when the docked stack is up.
                     return true;
                 }
             }
@@ -1819,7 +1833,7 @@
         // Make sure that the user who owns this activity is started.  If not,
         // we will just leave it as is because someone should be bringing
         // another user's activities to the top of the stack.
-        if (mService.mStartedUsers.get(next.userId) == null) {
+        if (!mService.mUserController.hasStartedUserState(next.userId)) {
             Slog.w(TAG, "Skipping resume of top activity " + next
                     + ": user " + next.userId + " is stopped");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -2032,7 +2046,7 @@
             // Have the window manager re-evaluate the orientation of
             // the screen based on the new activity order.
             boolean notUpdated = true;
-            if (mStackSupervisor.isFrontStack(this)) {
+            if (mStackSupervisor.isFocusedStack(this)) {
                 Configuration config = mWindowManager.updateOrientationFromAppTokens(
                         mService.mConfiguration,
                         next.mayFreezeScreenLocked(next.app) ? next.appToken : null);
@@ -2779,14 +2793,15 @@
     }
 
     private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
-        if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) {
+        if (mStackSupervisor.isFocusedStack(this) && mService.mFocusedActivity == r) {
             ActivityRecord next = topRunningActivityLocked();
             final String myReason = reason + " adjustFocus";
             if (next != r) {
                 if (next != null && (mStackId == FREEFORM_WORKSPACE_STACK_ID
-                        || mStackId == DOCKED_STACK_ID)) {
-                    // For freeform and docked stacks we always keep the focus within the stack as
-                    // long as there is a running activity in the stack that we can adjust focus to.
+                        || mStackId == DOCKED_STACK_ID || mStackId == PINNED_STACK_ID)) {
+                    // For freeform, docked, and pinned stacks we always keep the focus within the
+                    // stack as long as there is a running activity in the stack that we can adjust
+                    // focus to.
                     mService.setFocusedActivityLocked(next, myReason);
                     return;
                 } else {
@@ -3385,7 +3400,7 @@
         if (task != null && task.removeActivity(r)) {
             if (DEBUG_STACK) Slog.i(TAG_STACK,
                     "removeActivityFromHistoryLocked: last activity removed from " + this);
-            if (mStackSupervisor.isFrontStack(this) && task == topTask() &&
+            if (mStackSupervisor.isFocusedStack(this) && task == topTask() &&
                     task.isOverHomeStack()) {
                 mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), reason);
             }
@@ -4138,9 +4153,7 @@
         if ((taskChanges & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
             final int oldSmallest = oldTaskOverride.smallestScreenWidthDp;
             final int newSmallest = taskConfig.smallestScreenWidthDp;
-            final boolean crosses = record.crossesHorizontalSizeThreshold(oldSmallest, newSmallest)
-                    || record.crossesVerticalSizeThreshold(oldSmallest, newSmallest);
-            if (!crosses) {
+            if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
                 taskChanges &= ~ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
             }
         }
@@ -4366,6 +4379,7 @@
 
             RunningTaskInfo ci = new RunningTaskInfo();
             ci.id = task.taskId;
+            ci.stackId = mStackId;
             ci.baseActivity = r.intent.getComponent();
             ci.topActivity = top.intent.getComponent();
             ci.lastActiveTime = task.lastActiveTime;
@@ -4558,7 +4572,7 @@
         if (mTaskHistory.isEmpty()) {
             if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
             // We only need to adjust focused stack if this stack is in focus.
-            if (isOnHomeDisplay() && mStackSupervisor.isFrontStack(this)) {
+            if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
                 if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
@@ -4633,6 +4647,51 @@
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
+    void setFocusAndResumeStateIfNeeded(
+            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
+        // If the activity had focus before move focus to this stack.
+        if (setFocus) {
+            // If the activity owns the last resumed activity, transfer that together,
+            // so that we don't resume the same activity again in the new stack.
+            // Apps may depend on onResume()/onPause() being called in pairs.
+            if (setResume) {
+                mResumedActivity = r;
+                // Move the stack in which we are placing the activity to the front. We don't use
+                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
+                // already focused, the call will short-circuit and do nothing.
+                moveToFront(reason);
+            } else {
+                // We need to not only move the stack to the front, but also have the activity
+                // focused. This will achieve both goals.
+                mService.setFocusedActivityLocked(r, reason);
+            }
+        }
+    }
+
+    /**
+     * Moves the input activity from its current stack to this one.
+     * NOTE: The current task of the activity isn't moved to this stack. Instead a new task is
+     * created on this stack which the activity is added to.
+     * */
+    void moveActivityToStack(ActivityRecord r) {
+        final ActivityStack prevStack = r.task.stack;
+        if (prevStack.mStackId == mStackId) {
+            // You are already in the right stack silly...
+            return;
+        }
+
+        final boolean wasFocused = mStackSupervisor.isFocusedStack(prevStack)
+                && (mStackSupervisor.topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+
+        final TaskRecord task = createTaskRecord(
+                mStackSupervisor.getNextTaskId(), r.info, r.intent, null, null, true);
+        r.setTask(task, null);
+        task.addActivityToTop(r);
+        setAppTask(r, task);
+        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+    }
+
     private void setAppTask(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
         task.updateOverrideConfiguration(bounds);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 54ac58a..1cd71a1 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -296,10 +295,6 @@
     /** Set when we have taken too long waiting to go to sleep. */
     boolean mSleepTimeout = false;
 
-    /** Indicates if we are running on a Leanback-only (TV) device. Only initialized after
-     * setWindowManager is called. **/
-    private boolean mLeanbackOnlyDevice;
-
     /**
      * We don't want to allow the device to go to sleep while in the process
      * of launching an activity.  This is primarily to allow alarm intent
@@ -447,9 +442,6 @@
             mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
 
             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
-
-            // Initialize this here, now that we can get a valid reference to PackageManager.
-            mLeanbackOnlyDevice = isLeanbackOnlyDevice();
         }
     }
 
@@ -466,10 +458,7 @@
         return mLastFocusedStack;
     }
 
-    /** Top of all visible stacks is/should always be equal to the focused stack.
-     * Use {@link ActivityStack#isStackVisibleLocked} to determine if a specific
-     * stack is visible or not. */
-    boolean isFrontStack(ActivityStack stack) {
+    boolean isFocusedStack(ActivityStack stack) {
         if (stack == null) {
             return false;
         }
@@ -481,18 +470,22 @@
         return stack == mFocusedStack;
     }
 
-    void setFocusStack(String reason, ActivityStack lastFocusedStack) {
-        ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
-        final int topNdx = stacks.size() - 1;
-        if (topNdx <= 0) {
-            return;
+    /** The top most stack. */
+    boolean isFrontStack(ActivityStack stack) {
+        if (stack == null) {
+            return false;
         }
 
-        final ActivityStack topStack = stacks.get(topNdx);
-        mFocusedStack = topStack;
-        if (lastFocusedStack != null) {
-            mLastFocusedStack = lastFocusedStack;
+        final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
+        if (parent != null) {
+            stack = parent.task.stack;
         }
+        return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
+    }
+
+    void setFocusStack(String reason, ActivityStack focusedStack) {
+        mLastFocusedStack = mFocusedStack;
+        mFocusedStack = focusedStack;
 
         EventLogTags.writeAmFocusedStack(
                 mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
@@ -650,7 +643,7 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!isFrontStack(stack)) {
+                if (!isFocusedStack(stack)) {
                     continue;
                 }
                 ActivityRecord hr = stack.topRunningActivityLocked();
@@ -681,7 +674,7 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!isFrontStack(stack) || stack.numActivities() == 0) {
+                if (!isFocusedStack(stack) || stack.numActivities() == 0) {
                     continue;
                 }
                 final ActivityRecord resumedActivity = stack.mResumedActivity;
@@ -700,7 +693,7 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (isFrontStack(stack)) {
+                if (isFocusedStack(stack)) {
                     final ActivityRecord r = stack.mResumedActivity;
                     if (r != null && r.state != RESUMED) {
                         return false;
@@ -745,7 +738,7 @@
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (!isFrontStack(stack) && stack.mResumedActivity != null) {
+                if (!isFocusedStack(stack) && stack.mResumedActivity != null) {
                     if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                             " mResumedActivity=" + stack.mResumedActivity);
                     someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
@@ -1382,7 +1375,7 @@
         // launching the initial activity (that is, home), so that it can have
         // a chance to initialize itself while in the background, making the
         // switch back to it faster and look better.
-        if (isFrontStack(stack)) {
+        if (isFocusedStack(stack)) {
             mService.startSetupActivityLocked();
         }
 
@@ -1781,70 +1774,68 @@
     ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds) {
         final TaskRecord task = r.task;
 
-        // On leanback only devices we should keep all activities in the same stack.
-        if (!mLeanbackOnlyDevice &&
-                (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+        if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+            return mHomeStack;
+        }
 
-            ActivityStack stack;
+        ActivityStack stack;
 
-            if (task != null && task.stack != null) {
-                stack = task.stack;
-                if (stack.isOnHomeDisplay()) {
-                    if (mFocusedStack != stack) {
-                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                                "computeStackFocus: Setting " + "focused stack to r=" + r
-                                + " task=" + task);
-                    } else {
-                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Focused stack already=" + mFocusedStack);
-                    }
-                }
-                return stack;
-            }
-
-            final ActivityContainer container = r.mInitialActivityContainer;
-            if (container != null) {
-                // The first time put it on the desired stack, after this put on task stack.
-                r.mInitialActivityContainer = null;
-                return container.mStack;
-            }
-
-            // The fullscreen stack can contain any task regardless of if the task is resizeable
-            // or not. So, we let the task go in the fullscreen task if it is the focus stack.
-            // If the freeform stack has focus, and the activity to be launched is resizeable,
-            // we can also put it in the focused stack.
-            final boolean canUseFocusedStack =
-                    mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID
-                    || mFocusedStack.mStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable;
-            if (canUseFocusedStack
-                    && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
-                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                        "computeStackFocus: Have a focused stack=" + mFocusedStack);
-                return mFocusedStack;
-            }
-
-            // We first try to put the task in the first dynamic stack.
-            final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
-            for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                stack = homeDisplayStacks.get(stackNdx);
-                final boolean isDynamicStack = stack.mStackId >= FIRST_DYNAMIC_STACK_ID;
-                if (isDynamicStack) {
+        if (task != null && task.stack != null) {
+            stack = task.stack;
+            if (stack.isOnHomeDisplay()) {
+                if (mFocusedStack != stack) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
-                            "computeStackFocus: Setting focused stack=" + stack);
-                    return stack;
+                            "computeStackFocus: Setting " + "focused stack to r=" + r
+                            + " task=" + task);
+                } else {
+                    if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Focused stack already=" + mFocusedStack);
                 }
             }
-
-            // If there is no suitable dynamic stack then we figure out which static stack to use.
-            final int stackId = task != null ? task.getLaunchStackId() :
-                        bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
-                                         FULLSCREEN_WORKSPACE_STACK_ID;
-            stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
-                    + r + " stackId=" + stack.mStackId);
             return stack;
         }
-        return mHomeStack;
+
+        final ActivityContainer container = r.mInitialActivityContainer;
+        if (container != null) {
+            // The first time put it on the desired stack, after this put on task stack.
+            r.mInitialActivityContainer = null;
+            return container.mStack;
+        }
+
+        // The fullscreen stack can contain any task regardless of if the task is resizeable
+        // or not. So, we let the task go in the fullscreen task if it is the focus stack.
+        // If the freeform stack has focus, and the activity to be launched is resizeable,
+        // we can also put it in the focused stack.
+        final boolean canUseFocusedStack =
+                mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID
+                || mFocusedStack.mStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable;
+        if (canUseFocusedStack
+                && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                    "computeStackFocus: Have a focused stack=" + mFocusedStack);
+            return mFocusedStack;
+        }
+
+        // We first try to put the task in the first dynamic stack.
+        final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
+        for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            stack = homeDisplayStacks.get(stackNdx);
+            final boolean isDynamicStack = stack.mStackId >= FIRST_DYNAMIC_STACK_ID;
+            if (isDynamicStack) {
+                if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
+                        "computeStackFocus: Setting focused stack=" + stack);
+                return stack;
+            }
+        }
+
+        // If there is no suitable dynamic stack then we figure out which static stack to use.
+        final int stackId = task != null ? task.getLaunchStackId() :
+                    bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
+                                     FULLSCREEN_WORKSPACE_STACK_ID;
+        stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
+        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
+                + r + " stackId=" + stack.mStackId);
+        return stack;
     }
 
     boolean setFocusedStack(ActivityRecord r, String reason) {
@@ -2631,7 +2622,7 @@
             r.idle = true;
 
             //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
-            if (isFrontStack(r.task.stack) || fromTimeout) {
+            if (isFocusedStack(r.task.stack) || fromTimeout) {
                 booting = checkFinishBootingLocked();
             }
         }
@@ -2693,7 +2684,7 @@
             // Complete user switch
             if (startingUsers != null) {
                 for (int i = 0; i < startingUsers.size(); i++) {
-                    mService.finishUserSwitch(startingUsers.get(i));
+                    mService.mUserController.finishUserSwitch(startingUsers.get(i));
                 }
             }
             // Complete starting up of background users
@@ -2701,7 +2692,7 @@
                 startingUsers = new ArrayList<UserState>(mStartingBackgroundUsers);
                 mStartingBackgroundUsers.clear();
                 for (int i = 0; i < startingUsers.size(); i++) {
-                    mService.finishUserBoot(startingUsers.get(i));
+                    mService.mUserController.finishUserBoot(startingUsers.get(i));
                 }
             }
         }
@@ -2759,8 +2750,7 @@
         boolean didSomething = false;
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            final int numStacks = stacks.size();
-            for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) {
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 if (stack.finishDisabledPackageActivitiesLocked(
                         packageName, filterByClasses, doit, evenPersistent, userId)) {
@@ -2784,7 +2774,7 @@
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
-                if (isFrontStack(stack)) {
+                if (isFocusedStack(stack)) {
                     if (stack.mResumedActivity != null) {
                         fgApp = stack.mResumedActivity.app;
                     } else if (stack.mPausingActivity != null) {
@@ -2816,7 +2806,7 @@
         }
         // Do targetStack first.
         boolean result = false;
-        if (isFrontStack(targetStack)) {
+        if (isFocusedStack(targetStack)) {
             result = targetStack.resumeTopActivityLocked(target, targetOptions);
         }
 
@@ -2828,7 +2818,7 @@
                     // Already started above.
                     continue;
                 }
-                if (isFrontStack(stack)) {
+                if (isFocusedStack(stack)) {
                     stack.resumeTopActivityLocked(null);
                 }
             }
@@ -2886,13 +2876,16 @@
         }
 
         if (stackId != task.stack.mStackId) {
-            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, FORCE_FOCUS, reason);
-        } else {
-            task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
-                task.getTopActivity() == null ? null : task.getTopActivity().appTimeTracker,
-                reason);
+            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+
+            // moveTaskToStackUncheckedLocked() should already placed the task on top,
+            // still need moveTaskToFrontLocked() below for any transition settings.
         }
 
+        final ActivityRecord r = task.getTopActivity();
+        task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+                r == null ? null : r.appTimeTracker, reason);
+
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
@@ -2999,84 +2992,87 @@
         }
 
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
 
-        ActivityRecord r = stack.topRunningActivityLocked();
-
-        mTmpBounds.clear();
-        mTmpConfigs.clear();
-        ArrayList<TaskRecord> tasks = stack.getAllTasks();
-        for (int i = tasks.size() - 1; i >= 0; i--) {
-            TaskRecord task = tasks.get(i);
-            if (task.mResizeable) {
-                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                    // For freeform stack we don't adjust the size of the tasks to match that
-                    // of the stack, but we do try to make sure the tasks are still contained
-                    // with the bounds of the stack.
-                    tempRect2.set(task.mBounds);
-                    fitWithinBounds(tempRect2, bounds);
-                    task.updateOverrideConfiguration(tempRect2);
-                } else {
-                    task.updateOverrideConfiguration(bounds);
-                }
-            }
-
-            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
-            mTmpBounds.put(task.taskId, task.mBounds);
-        }
-        stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
-        if (stack.mStackId == DOCKED_STACK_ID) {
-            // Dock stack funness...Yay!
-            if (stack.mFullscreen) {
-                // The dock stack went fullscreen which is kinda like dismissing it.
-                // In this case we make all other static stacks fullscreen and move all
-                // docked stack tasks to the fullscreen stack.
-                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    if (i != DOCKED_STACK_ID && getStack(i) != null) {
-                        resizeStackLocked(i, null, preserveWindows, true);
+            mTmpBounds.clear();
+            mTmpConfigs.clear();
+            ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                TaskRecord task = tasks.get(i);
+                if (task.mResizeable) {
+                    if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                        // For freeform stack we don't adjust the size of the tasks to match that
+                        // of the stack, but we do try to make sure the tasks are still contained
+                        // with the bounds of the stack.
+                        tempRect2.set(task.mBounds);
+                        fitWithinBounds(tempRect2, bounds);
+                        task.updateOverrideConfiguration(tempRect2);
+                    } else {
+                        task.updateOverrideConfiguration(bounds);
                     }
                 }
 
-                final int count = tasks.size();
-                for (int i = 0; i < count; i++) {
-                    moveTaskToStackLocked(tasks.get(i).taskId,
-                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS);
-                }
+                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+                mTmpBounds.put(task.taskId, task.mBounds);
+            }
+            stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
+            if (stack.mStackId == DOCKED_STACK_ID) {
+                // Dock stack funness...Yay!
+                if (stack.mFullscreen) {
+                    // The dock stack went fullscreen which is kinda like dismissing it.
+                    // In this case we make all other static stacks fullscreen and move all
+                    // docked stack tasks to the fullscreen stack.
+                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                        if (i != DOCKED_STACK_ID && getStack(i) != null) {
+                            resizeStackLocked(i, null, preserveWindows, true);
+                        }
+                    }
 
-                // stack shouldn't contain anymore activities, so nothing to resume.
-                r = null;
-            } else {
-                // Docked stacks occupy a dedicated region on screen so the size of all other
-                // static stacks need to be adjusted so they don't overlap with the docked stack.
-                // We get the bounds to use from window manager which has been adjusted for any
-                // screen controls and is also the same for all stacks.
-                mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+                    final int count = tasks.size();
+                    for (int i = 0; i < count; i++) {
+                        moveTaskToStackLocked(tasks.get(i).taskId,
+                                FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack");
+                    }
 
-                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                    if (i != DOCKED_STACK_ID) {
-                        ActivityStack otherStack = getStack(i);
-                        if (otherStack != null) {
-                            resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
+                    // stack shouldn't contain anymore activities, so nothing to resume.
+                    r = null;
+                } else {
+                    // Docked stacks occupy a dedicated region on screen so the size of all other
+                    // static stacks need to be adjusted so they don't overlap with the docked stack.
+                    // We get the bounds to use from window manager which has been adjusted for any
+                    // screen controls and is also the same for all stacks.
+                    mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+
+                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                        if (i != DOCKED_STACK_ID) {
+                            ActivityStack otherStack = getStack(i);
+                            if (otherStack != null) {
+                                resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
+                            }
                         }
                     }
                 }
+                // Since we are resizing the stack, all other operations should strive to preserve
+                // windows.
+                preserveWindows = true;
             }
-            // Since we are resizing the stack, all other operations should strive to preserve
-            // windows.
-            preserveWindows = true;
-        }
-        stack.setBounds(bounds);
+            stack.setBounds(bounds);
 
-        if (r != null) {
-            final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
-            // And we need to make sure at this point that all other activities
-            // are made visible with the correct configuration.
-            ensureActivitiesVisibleLocked(r, 0, preserveWindows);
-            if (!updated) {
-                resumeTopActivitiesLocked(stack, null, null);
+            if (r != null) {
+                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
+                // And we need to make sure at this point that all other activities
+                // are made visible with the correct configuration.
+                ensureActivitiesVisibleLocked(r, 0, preserveWindows);
+                if (!updated) {
+                    resumeTopActivitiesLocked(stack, null, null);
+                }
             }
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
         }
-
-        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
@@ -3199,7 +3195,7 @@
      */
     private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
         if (stackId == INVALID_STACK_ID) {
-            stackId = mLeanbackOnlyDevice ? mHomeStack.mStackId : task.getLaunchStackId();
+            stackId = task.getLaunchStackId();
         }
         if (task.stack != null) {
             // Task has already been restored once. See if we need to do anything more
@@ -3248,7 +3244,7 @@
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
         final ActivityRecord r = task.getTopActivity();
-        final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
+        final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
 
         final boolean resizeable = task.mResizeable;
@@ -3266,35 +3262,21 @@
 
         // If the task had focus before (or we're requested to move focus),
         // move focus to the new stack.
-        if (forceFocus || wasFocused) {
-            // If the task owns the last resumed activity, transfer that together,
-            // so that we don't resume the same activity again in the new stack.
-            // Apps may depend on onResume()/onPause() being called in pairs.
-            if (wasResumed) {
-                stack.mResumedActivity = r;
-                // Move the stack in which we are placing the task to the front. We don't use
-                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
-                // already focused, the call will short-circuit and do nothing.
-                stack.moveToFront(reason);
-            } else {
-                // We need to not only move the stack to the front, but also have the activity
-                // focused. This will achieve both goals.
-                mService.setFocusedActivityLocked(r, reason);
-            }
-
-        }
+        stack.setFocusAndResumeStateIfNeeded(
+                r, forceFocus || wasFocused, wasResumed, reason);
 
         return stack;
     }
 
-    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus) {
+    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
+            String reason) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
             return;
         }
-        final String reason = "moveTaskToStack";
-        if (stackId == DOCKED_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+        if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID
+                || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
             // We are about to relaunch the activity because its configuration changed due to
             // being maximized, i.e. size change. The activity will first remove the old window
             // and then add a new one. This call will tell window manager about this, so it can
@@ -3305,7 +3287,8 @@
             mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
         }
         final ActivityStack stack =
-                moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason);
+                moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus,
+                        "moveTaskToStack:" + reason);
 
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
@@ -3315,7 +3298,7 @@
                 && task.mBounds == null && task.mLastNonFullscreenBounds != null) {
             resizeTaskLocked(task, task.mLastNonFullscreenBounds,
                     RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
-        } else if (stackId == DOCKED_STACK_ID) {
+        } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) {
             resizeTaskLocked(task, stack.mBounds,
                     RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS);
         }
@@ -3326,6 +3309,47 @@
         resumeTopActivitiesLocked();
     }
 
+    boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
+        final ActivityStack stack = getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
+        if (stack == null) {
+            throw new IllegalArgumentException(
+                    "moveTopStackActivityToPinnedStackLocked: Unknown stackId=" + stackId);
+        }
+
+        final ActivityRecord r = stack.topRunningActivityLocked();
+        if (r == null) {
+            Slog.w(TAG, "moveTopStackActivityToPinnedStackLocked: No top running activity"
+                    + " in stack=" + stack);
+            return false;
+        }
+
+        if (!r.info.supportsPip) {
+            Slog.w(TAG,
+                    "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
+                    + " r=" + r);
+            return false;
+        }
+
+        final TaskRecord task = r.task;
+        if (task.mActivities.size() == 1) {
+            // There is only one activity in the task. So, we can just move the task over to the
+            // pinned stack without re-parenting the activity in a different task.
+            moveTaskToStackLocked(task.taskId, PINNED_STACK_ID, ON_TOP, FORCE_FOCUS,
+                    "moveTopActivityToPinnedStack");
+        } else {
+            final ActivityStack pinnedStack = getStack(PINNED_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
+            pinnedStack.moveActivityToStack(r);
+        }
+
+        resizeStackLocked(PINNED_STACK_ID, bounds, PRESERVE_WINDOWS, true);
+
+        // The task might have already been running and its visibility needs to be synchronized with
+        // the visibility of the stack / windows.
+        ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
+        resumeTopActivitiesLocked();
+        return true;
+    }
+
     void positionTaskInStackLocked(int taskId, int stackId, int position) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
@@ -3446,7 +3470,7 @@
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack stack = stacks.get(stackNdx);
                 stack.awakeFromSleepingLocked();
-                if (isFrontStack(stack)) {
+                if (isFocusedStack(stack)) {
                     resumeTopActivitiesLocked();
                 }
             }
@@ -3513,7 +3537,7 @@
 
     boolean reportResumedActivityLocked(ActivityRecord r) {
         final ActivityStack stack = r.task.stack;
-        if (isFrontStack(stack)) {
+        if (isFocusedStack(stack)) {
             mService.updateUsageStats(r, true);
         }
         if (allResumedActivitiesComplete()) {
@@ -3756,10 +3780,7 @@
     /** Checks whether the userid is a profile of the current user. */
     boolean isCurrentProfileLocked(int userId) {
         if (userId == mCurrentUser) return true;
-        for (int i = 0; i < mService.mCurrentProfileIds.length; i++) {
-            if (mService.mCurrentProfileIds[i] == userId) return true;
-        }
-        return false;
+        return mService.mUserController.isCurrentProfileLocked(userId);
     }
 
     /** Checks whether the activity should be shown for current user. */
@@ -3809,7 +3830,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 final ActivityRecord r = stack.topRunningActivityLocked();
                 final ActivityState state = r == null ? DESTROYED : r.state;
-                if (isFrontStack(stack)) {
+                if (isFocusedStack(stack)) {
                     if (r == null) Slog.e(TAG,
                             "validateTop...: null top activity, stack=" + stack);
                     else {
@@ -4928,18 +4949,6 @@
         }
     }
 
-    private boolean isLeanbackOnlyDevice() {
-        boolean onLeanbackOnly = false;
-        try {
-            onLeanbackOnly = AppGlobals.getPackageManager().hasSystemFeature(
-                    PackageManager.FEATURE_LEANBACK_ONLY);
-        } catch (RemoteException e) {
-            // noop
-        }
-
-        return onLeanbackOnly;
-    }
-
     /**
      * Adjust bounds to stay within stack bounds.
      *
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 5b46799..6ed880e 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -248,7 +248,7 @@
                 boolean sendFinish = finishedReceiver != null;
                 int userId = key.userId;
                 if (userId == UserHandle.USER_CURRENT) {
-                    userId = owner.getCurrentUserIdLocked();
+                    userId = owner.mUserController.getCurrentUserIdLocked();
                 }
                 switch (key.type) {
                     case ActivityManager.INTENT_SENDER_ACTIVITY:
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index fe87a93..120b40c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -20,6 +20,7 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
@@ -317,7 +318,7 @@
         mNextAffiliateTaskId = nextTaskId;
         mCallingUid = callingUid;
         mCallingPackage = callingPackage;
-        mResizeable = resizeable;
+        mResizeable = resizeable || mService.mForceResizableActivites;
         mPrivileged = privileged;
         ActivityInfo info = mActivities.get(0).info;
         mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1;
@@ -419,7 +420,7 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = info.resizeable;
+        mResizeable = info.resizeable || mService.mForceResizableActivites;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -625,6 +626,9 @@
         // Only set this based on the first activity
         if (mActivities.isEmpty()) {
             taskType = r.mActivityType;
+            if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivites) {
+                mResizeable = r.info.resizeable;
+            }
             isPersistable = r.isPersistable();
             mCallingUid = r.launchedFromUid;
             mCallingPackage = r.launchedFromPackage;
@@ -1189,14 +1193,14 @@
 
         mFullscreen = bounds == null;
         if (mFullscreen) {
-            if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
+            if (mBounds != null && stack.mPersistTaskBounds) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mBounds = null;
             mOverrideConfig = Configuration.EMPTY;
         } else {
             mBounds = new Rect(bounds);
-            if (stack == null || stack.mStackId != DOCKED_STACK_ID) {
+            if (stack == null || stack.mPersistTaskBounds) {
                 mLastNonFullscreenBounds = mBounds;
             }
 
@@ -1235,11 +1239,12 @@
 
     /** Returns the bounds that should be used to launch this task. */
     Rect getLaunchBounds() {
+        final int stackId = stack.mStackId;
         if (stack == null
-                || stack.mStackId == HOME_STACK_ID
-                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+                || stackId == HOME_STACK_ID
+                || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
             return (mResizeable && stack != null) ? stack.mBounds : null;
-        } else if (stack.mStackId == DOCKED_STACK_ID) {
+        } else if (!stack.mPersistTaskBounds) {
             return stack.mBounds;
         }
         return mLastNonFullscreenBounds;
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
new file mode 100644
index 0000000..ff74d83
--- /dev/null
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -0,0 +1,862 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server.am;
+
+import static android.Manifest.permission.INTERACT_ACROSS_USERS;
+import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.ActivityManager.USER_OP_IS_CURRENT;
+import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
+import static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
+import static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
+import static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
+import static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.IStopUserCallback;
+import android.app.IUserSwitchObserver;
+import android.content.IIntentReceiver;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.BatteryStats;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.Process;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.R;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.pm.UserManagerService;
+
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Helper class for {@link ActivityManagerService} responsible for multi-user functionality.
+ */
+final class UserController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "UserController" : TAG_AM;
+    // Maximum number of users we allow to be running at a time.
+    static final int MAX_RUNNING_USERS = 3;
+
+    // Amount of time we wait for observers to handle a user switch before
+    // giving up on them and unfreezing the screen.
+    static final int USER_SWITCH_TIMEOUT = 2 * 1000;
+
+    private final ActivityManagerService mService;
+    private final Handler mHandler;
+
+    // Holds the current foreground user's id
+    int mCurrentUserId = 0;
+    // Holds the target user's id during a user switch
+    int mTargetUserId = UserHandle.USER_NULL;
+
+    /**
+     * Which users have been started, so are allowed to run code.
+     */
+    private final SparseArray<UserState> mStartedUsers = new SparseArray<>();
+    /**
+     * LRU list of history of current users.  Most recently current is at the end.
+     */
+    private final ArrayList<Integer> mUserLru = new ArrayList<>();
+
+    /**
+     * Constant array of the users that are currently started.
+     */
+    private int[] mStartedUserArray = new int[] { 0 };
+
+    // If there are multiple profiles for the current user, their ids are here
+    // Currently only the primary user can have managed profiles
+    int[] mCurrentProfileIds = new int[] {}; // Accessed by ActivityStack
+
+    /**
+     * Mapping from each known user ID to the profile group ID it is associated with.
+     */
+    private final SparseIntArray mUserProfileGroupIdsSelfLocked = new SparseIntArray();
+
+    /**
+     * Registered observers of the user switching mechanics.
+     */
+    final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
+            = new RemoteCallbackList<>();
+
+    /**
+     * Currently active user switch.
+     */
+    Object mCurUserSwitchCallback;
+
+    UserController(ActivityManagerService service) {
+        mService = service;
+        mHandler = mService.mHandler;
+        // User 0 is the first and only user that runs at boot.
+        mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
+        mUserLru.add(UserHandle.USER_SYSTEM);
+        updateStartedUserArrayLocked();
+    }
+
+    void finishUserSwitch(UserState uss) {
+        synchronized (mService) {
+            finishUserBoot(uss);
+
+            startProfilesLocked();
+
+            int num = mUserLru.size();
+            int i = 0;
+            while (num > MAX_RUNNING_USERS && i < mUserLru.size()) {
+                Integer oldUserId = mUserLru.get(i);
+                UserState oldUss = mStartedUsers.get(oldUserId);
+                if (oldUss == null) {
+                    // Shouldn't happen, but be sane if it does.
+                    mUserLru.remove(i);
+                    num--;
+                    continue;
+                }
+                if (oldUss.mState == UserState.STATE_STOPPING
+                        || oldUss.mState == UserState.STATE_SHUTDOWN) {
+                    // This user is already stopping, doesn't count.
+                    num--;
+                    i++;
+                    continue;
+                }
+                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
+                    // Owner/System user and current user can't be stopped. We count it as running
+                    // when it is not a pure system user.
+                    if (UserInfo.isSystemOnly(oldUserId)) {
+                        num--;
+                    }
+                    i++;
+                    continue;
+                }
+                // This is a user to be stopped.
+                stopUserLocked(oldUserId, null);
+                num--;
+                i++;
+            }
+        }
+    }
+
+    void finishUserBoot(UserState uss) {
+        synchronized (mService) {
+            if (uss.mState == UserState.STATE_BOOTING
+                    && mStartedUsers.get(uss.mHandle.getIdentifier()) == uss) {
+                uss.mState = UserState.STATE_RUNNING;
+                final int userId = uss.mHandle.getIdentifier();
+                Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                mService.broadcastIntentLocked(null, null, intent,
+                        null, null, 0, null, null,
+                        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                        AppOpsManager.OP_NONE, null, true, false, ActivityManagerService.MY_PID,
+                        Process.SYSTEM_UID, userId);
+            }
+        }
+    }
+
+    int stopUser(final int userId, final IStopUserCallback callback) {
+        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: switchUser() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        if (userId < 0 || userId == UserHandle.USER_SYSTEM) {
+            throw new IllegalArgumentException("Can't stop system user " + userId);
+        }
+        mService.enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES,
+                userId);
+        synchronized (mService) {
+            return stopUserLocked(userId, callback);
+        }
+    }
+
+    private int stopUserLocked(final int userId, final IStopUserCallback callback) {
+        if (DEBUG_MU) Slog.i(TAG, "stopUserLocked userId=" + userId);
+        if (mCurrentUserId == userId && mTargetUserId == UserHandle.USER_NULL) {
+            return USER_OP_IS_CURRENT;
+        }
+
+        final UserState uss = mStartedUsers.get(userId);
+        if (uss == null) {
+            // User is not started, nothing to do...  but we do need to
+            // callback if requested.
+            if (callback != null) {
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            callback.userStopped(userId);
+                        } catch (RemoteException e) {
+                        }
+                    }
+                });
+            }
+            return USER_OP_SUCCESS;
+        }
+
+        if (callback != null) {
+            uss.mStopCallbacks.add(callback);
+        }
+
+        if (uss.mState != UserState.STATE_STOPPING
+                && uss.mState != UserState.STATE_SHUTDOWN) {
+            uss.mState = UserState.STATE_STOPPING;
+            updateStartedUserArrayLocked();
+
+            long ident = Binder.clearCallingIdentity();
+            try {
+                // We are going to broadcast ACTION_USER_STOPPING and then
+                // once that is done send a final ACTION_SHUTDOWN and then
+                // stop the user.
+                final Intent stoppingIntent = new Intent(Intent.ACTION_USER_STOPPING);
+                stoppingIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                stoppingIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                stoppingIntent.putExtra(Intent.EXTRA_SHUTDOWN_USERSPACE_ONLY, true);
+                final Intent shutdownIntent = new Intent(Intent.ACTION_SHUTDOWN);
+                // This is the result receiver for the final shutdown broadcast.
+                final IIntentReceiver shutdownReceiver = new IIntentReceiver.Stub() {
+                    @Override
+                    public void performReceive(Intent intent, int resultCode, String data,
+                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                        finishUserStop(uss);
+                    }
+                };
+                // This is the result receiver for the initial stopping broadcast.
+                final IIntentReceiver stoppingReceiver = new IIntentReceiver.Stub() {
+                    @Override
+                    public void performReceive(Intent intent, int resultCode, String data,
+                            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
+                        // On to the next.
+                        synchronized (mService) {
+                            if (uss.mState != UserState.STATE_STOPPING) {
+                                // Whoops, we are being started back up.  Abort, abort!
+                                return;
+                            }
+                            uss.mState = UserState.STATE_SHUTDOWN;
+                        }
+                        mService.mBatteryStatsService.noteEvent(
+                                BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
+                                Integer.toString(userId), userId);
+                        mService.mSystemServiceManager.stopUser(userId);
+                        mService.broadcastIntentLocked(null, null, shutdownIntent,
+                                null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE,
+                                null, true, false, ActivityManagerService.MY_PID,
+                                android.os.Process.SYSTEM_UID, userId);
+                    }
+                };
+                // Kick things off.
+                mService.broadcastIntentLocked(null, null, stoppingIntent,
+                        null, stoppingReceiver, 0, null, null,
+                        new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
+                        null, true, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
+                        UserHandle.USER_ALL);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+
+        return USER_OP_SUCCESS;
+    }
+
+    void finishUserStop(UserState uss) {
+        final int userId = uss.mHandle.getIdentifier();
+        boolean stopped;
+        ArrayList<IStopUserCallback> callbacks;
+        synchronized (mService) {
+            callbacks = new ArrayList<>(uss.mStopCallbacks);
+            if (mStartedUsers.get(userId) != uss) {
+                stopped = false;
+            } else if (uss.mState != UserState.STATE_SHUTDOWN) {
+                stopped = false;
+            } else {
+                stopped = true;
+                // User can no longer run.
+                mStartedUsers.remove(userId);
+                mUserLru.remove(Integer.valueOf(userId));
+                updateStartedUserArrayLocked();
+
+                // Clean up all state and processes associated with the user.
+                // Kill all the processes for the user.
+                forceStopUserLocked(userId, "finish user");
+            }
+        }
+
+        for (int i = 0; i < callbacks.size(); i++) {
+            try {
+                if (stopped) callbacks.get(i).userStopped(userId);
+                else callbacks.get(i).userStopAborted(userId);
+            } catch (RemoteException e) {
+            }
+        }
+
+        if (stopped) {
+            mService.mSystemServiceManager.cleanupUser(userId);
+            synchronized (mService) {
+                mService.mStackSupervisor.removeUserLocked(userId);
+            }
+        }
+    }
+
+    private void forceStopUserLocked(int userId, String reason) {
+        mService.forceStopPackageLocked(null, -1, false, false, true, false, false,
+                userId, reason);
+        Intent intent = new Intent(Intent.ACTION_USER_STOPPED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                | Intent.FLAG_RECEIVER_FOREGROUND);
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+        mService.broadcastIntentLocked(null, null, intent,
+                null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                null, false, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
+                UserHandle.USER_ALL);
+    }
+
+
+    /**
+     * Stops the guest user if it has gone to the background.
+     */
+    private void stopGuestUserIfBackground() {
+        synchronized (mService) {
+            final int num = mUserLru.size();
+            for (int i = 0; i < num; i++) {
+                Integer oldUserId = mUserLru.get(i);
+                UserState oldUss = mStartedUsers.get(oldUserId);
+                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
+                        || oldUss.mState == UserState.STATE_STOPPING
+                        || oldUss.mState == UserState.STATE_SHUTDOWN) {
+                    continue;
+                }
+                UserInfo userInfo = getUserManagerLocked().getUserInfo(oldUserId);
+                if (userInfo.isGuest()) {
+                    // This is a user to be stopped.
+                    stopUserLocked(oldUserId, null);
+                    break;
+                }
+            }
+        }
+    }
+
+    void startProfilesLocked() {
+        if (DEBUG_MU) Slog.i(TAG, "startProfilesLocked");
+        List<UserInfo> profiles = getUserManagerLocked().getProfiles(
+                mCurrentUserId, false /* enabledOnly */);
+        List<UserInfo> profilesToStart = new ArrayList<>(profiles.size());
+        for (UserInfo user : profiles) {
+            if ((user.flags & UserInfo.FLAG_INITIALIZED) == UserInfo.FLAG_INITIALIZED
+                    && user.id != mCurrentUserId) {
+                profilesToStart.add(user);
+            }
+        }
+        final int profilesToStartSize = profilesToStart.size();
+        int i = 0;
+        for (; i < profilesToStartSize && i < (MAX_RUNNING_USERS - 1); ++i) {
+            startUser(profilesToStart.get(i).id, /* foreground= */ false);
+        }
+        if (i < profilesToStartSize) {
+            Slog.w(TAG, "More profiles than MAX_RUNNING_USERS");
+        }
+    }
+
+    private UserManagerService getUserManagerLocked() {
+        return mService.getUserManagerLocked();
+    }
+
+    boolean startUser(final int userId, final boolean foreground) {
+        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED) {
+            String msg = "Permission Denial: switchUser() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        if (DEBUG_MU) Slog.i(TAG, "starting userid:" + userId + " fore:" + foreground);
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (mService) {
+                final int oldUserId = mCurrentUserId;
+                if (oldUserId == userId) {
+                    return true;
+                }
+
+                mService.mStackSupervisor.setLockTaskModeLocked(null,
+                        ActivityManager.LOCK_TASK_MODE_NONE, "startUser", false);
+
+                final UserInfo userInfo = getUserManagerLocked().getUserInfo(userId);
+                if (userInfo == null) {
+                    Slog.w(TAG, "No user info for user #" + userId);
+                    return false;
+                }
+                if (foreground && userInfo.isManagedProfile()) {
+                    Slog.w(TAG, "Cannot switch to User #" + userId + ": not a full user");
+                    return false;
+                }
+
+                if (foreground) {
+                    mService.mWindowManager.startFreezingScreen(
+                            R.anim.screen_user_exit, R.anim.screen_user_enter);
+                }
+
+                boolean needStart = false;
+
+                // If the user we are switching to is not currently started, then
+                // we need to start it now.
+                if (mStartedUsers.get(userId) == null) {
+                    mStartedUsers.put(userId, new UserState(new UserHandle(userId), false));
+                    updateStartedUserArrayLocked();
+                    needStart = true;
+                }
+
+                final Integer userIdInt = userId;
+                mUserLru.remove(userIdInt);
+                mUserLru.add(userIdInt);
+
+                if (foreground) {
+                    mCurrentUserId = userId;
+                    mService.updateUserConfigurationLocked();
+                    mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
+                    updateCurrentProfileIdsLocked();
+                    mService.mWindowManager.setCurrentUser(userId, mCurrentProfileIds);
+                    // Once the internal notion of the active user has switched, we lock the device
+                    // with the option to show the user switcher on the keyguard.
+                    mService.mWindowManager.lockNow(null);
+                } else {
+                    final Integer currentUserIdInt = mCurrentUserId;
+                    updateCurrentProfileIdsLocked();
+                    mService.mWindowManager.setCurrentProfileIds(mCurrentProfileIds);
+                    mUserLru.remove(currentUserIdInt);
+                    mUserLru.add(currentUserIdInt);
+                }
+
+                final UserState uss = mStartedUsers.get(userId);
+
+                // Make sure user is in the started state.  If it is currently
+                // stopping, we need to knock that off.
+                if (uss.mState == UserState.STATE_STOPPING) {
+                    // If we are stopping, we haven't sent ACTION_SHUTDOWN,
+                    // so we can just fairly silently bring the user back from
+                    // the almost-dead.
+                    uss.mState = UserState.STATE_RUNNING;
+                    updateStartedUserArrayLocked();
+                    needStart = true;
+                } else if (uss.mState == UserState.STATE_SHUTDOWN) {
+                    // This means ACTION_SHUTDOWN has been sent, so we will
+                    // need to treat this as a new boot of the user.
+                    uss.mState = UserState.STATE_BOOTING;
+                    updateStartedUserArrayLocked();
+                    needStart = true;
+                }
+
+                if (uss.mState == UserState.STATE_BOOTING) {
+                    // Booting up a new user, need to tell system services about it.
+                    // Note that this is on the same handler as scheduling of broadcasts,
+                    // which is important because it needs to go first.
+                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_START_MSG, userId, 0));
+                }
+
+                if (foreground) {
+                    mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_CURRENT_MSG, userId,
+                            oldUserId));
+                    mHandler.removeMessages(REPORT_USER_SWITCH_MSG);
+                    mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+                    mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_MSG,
+                            oldUserId, userId, uss));
+                    mHandler.sendMessageDelayed(mHandler.obtainMessage(USER_SWITCH_TIMEOUT_MSG,
+                            oldUserId, userId, uss), USER_SWITCH_TIMEOUT);
+                }
+
+                if (needStart) {
+                    // Send USER_STARTED broadcast
+                    Intent intent = new Intent(Intent.ACTION_USER_STARTED);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
+                            | Intent.FLAG_RECEIVER_FOREGROUND);
+                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                    mService.broadcastIntentLocked(null, null, intent,
+                            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
+                            null, false, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
+                            userId);
+                }
+
+                if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
+                    if (userId != UserHandle.USER_SYSTEM) {
+                        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                        mService.broadcastIntentLocked(null, null, intent, null,
+                                new IIntentReceiver.Stub() {
+                                    public void performReceive(Intent intent, int resultCode,
+                                            String data, Bundle extras, boolean ordered,
+                                            boolean sticky, int sendingUser) {
+                                        onUserInitialized(uss, foreground, oldUserId, userId);
+                                    }
+                                }, 0, null, null, null, AppOpsManager.OP_NONE,
+                                null, true, false, ActivityManagerService.MY_PID,
+                                Process.SYSTEM_UID, userId);
+                        uss.initializing = true;
+                    } else {
+                        getUserManagerLocked().makeInitialized(userInfo.id);
+                    }
+                }
+
+                if (foreground) {
+                    if (!uss.initializing) {
+                        moveUserToForegroundLocked(uss, oldUserId, userId);
+                    }
+                } else {
+                    mService.mStackSupervisor.startBackgroundUserLocked(userId, uss);
+                }
+
+                if (needStart) {
+                    Intent intent = new Intent(Intent.ACTION_USER_STARTING);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                    intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                    mService.broadcastIntentLocked(null, null, intent,
+                            null, new IIntentReceiver.Stub() {
+                                @Override
+                                public void performReceive(Intent intent, int resultCode,
+                                        String data, Bundle extras, boolean ordered, boolean sticky,
+                                        int sendingUser) throws RemoteException {
+                                }
+                            }, 0, null, null,
+                            new String[]{INTERACT_ACROSS_USERS}, AppOpsManager.OP_NONE,
+                            null, true, false, ActivityManagerService.MY_PID, Process.SYSTEM_UID,
+                            UserHandle.USER_ALL);
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        return true;
+    }
+
+    void dispatchForegroundProfileChanged(int userId) {
+        final int observerCount = mUserSwitchObservers.beginBroadcast();
+        for (int i = 0; i < observerCount; i++) {
+            try {
+                mUserSwitchObservers.getBroadcastItem(i).onForegroundProfileSwitch(userId);
+            } catch (RemoteException e) {
+                // Ignore
+            }
+        }
+        mUserSwitchObservers.finishBroadcast();
+    }
+
+    /** Called on handler thread */
+    void dispatchUserSwitchComplete(int userId) {
+        final int observerCount = mUserSwitchObservers.beginBroadcast();
+        for (int i = 0; i < observerCount; i++) {
+            try {
+                mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId);
+            } catch (RemoteException e) {
+            }
+        }
+        mUserSwitchObservers.finishBroadcast();
+    }
+
+    void timeoutUserSwitch(UserState uss, int oldUserId, int newUserId) {
+        synchronized (mService) {
+            Slog.w(TAG, "User switch timeout: from " + oldUserId + " to " + newUserId);
+            sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+        }
+    }
+
+    void dispatchUserSwitch(final UserState uss, final int oldUserId,
+            final int newUserId) {
+        final int observerCount = mUserSwitchObservers.beginBroadcast();
+        if (observerCount > 0) {
+            final IRemoteCallback callback = new IRemoteCallback.Stub() {
+                int mCount = 0;
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    synchronized (mService) {
+                        if (mCurUserSwitchCallback == this) {
+                            mCount++;
+                            if (mCount == observerCount) {
+                                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+                            }
+                        }
+                    }
+                }
+            };
+            synchronized (mService) {
+                uss.switching = true;
+                mCurUserSwitchCallback = callback;
+            }
+            for (int i = 0; i < observerCount; i++) {
+                try {
+                    mUserSwitchObservers.getBroadcastItem(i).onUserSwitching(
+                            newUserId, callback);
+                } catch (RemoteException e) {
+                }
+            }
+        } else {
+            synchronized (mService) {
+                sendContinueUserSwitchLocked(uss, oldUserId, newUserId);
+            }
+        }
+        mUserSwitchObservers.finishBroadcast();
+    }
+
+    void sendContinueUserSwitchLocked(UserState uss, int oldUserId, int newUserId) {
+        mCurUserSwitchCallback = null;
+        mHandler.removeMessages(USER_SWITCH_TIMEOUT_MSG);
+        mHandler.sendMessage(mHandler.obtainMessage(ActivityManagerService.CONTINUE_USER_SWITCH_MSG,
+                oldUserId, newUserId, uss));
+    }
+
+    void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
+        completeSwitchAndInitialize(uss, newUserId, false, true);
+    }
+
+    void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
+        synchronized (mService) {
+            if (foreground) {
+                moveUserToForegroundLocked(uss, oldUserId, newUserId);
+            }
+        }
+        completeSwitchAndInitialize(uss, newUserId, true, false);
+    }
+
+    void completeSwitchAndInitialize(UserState uss, int newUserId,
+            boolean clearInitializing, boolean clearSwitching) {
+        boolean unfrozen = false;
+        synchronized (mService) {
+            if (clearInitializing) {
+                uss.initializing = false;
+                getUserManagerLocked().makeInitialized(uss.mHandle.getIdentifier());
+            }
+            if (clearSwitching) {
+                uss.switching = false;
+            }
+            if (!uss.switching && !uss.initializing) {
+                mService.mWindowManager.stopFreezingScreen();
+                unfrozen = true;
+            }
+        }
+        if (unfrozen) {
+            mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
+                    newUserId, 0));
+        }
+        stopGuestUserIfBackground();
+    }
+
+    void moveUserToForegroundLocked(UserState uss, int oldUserId, int newUserId) {
+        boolean homeInFront = mService.mStackSupervisor.switchUserLocked(newUserId, uss);
+        if (homeInFront) {
+            mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
+        } else {
+            mService.mStackSupervisor.resumeTopActivitiesLocked();
+        }
+        EventLogTags.writeAmSwitchUser(newUserId);
+        getUserManagerLocked().onUserForeground(newUserId);
+        mService.sendUserSwitchBroadcastsLocked(oldUserId, newUserId);
+    }
+
+    void registerUserSwitchObserver(IUserSwitchObserver observer) {
+        if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
+                != PackageManager.PERMISSION_GRANTED) {
+            final String msg = "Permission Denial: registerUserSwitchObserver() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + INTERACT_ACROSS_USERS_FULL;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        mUserSwitchObservers.register(observer);
+    }
+
+    void unregisterUserSwitchObserver(IUserSwitchObserver observer) {
+        mUserSwitchObservers.unregister(observer);
+    }
+
+    UserState getStartedUserState(int userId) {
+        return mStartedUsers.get(userId);
+    }
+
+    boolean hasStartedUserState(int userId) {
+        return mStartedUsers.get(userId) != null;
+    }
+
+    private void updateStartedUserArrayLocked() {
+        int num = 0;
+        for (int i = 0; i < mStartedUsers.size(); i++) {
+            UserState uss = mStartedUsers.valueAt(i);
+            // This list does not include stopping users.
+            if (uss.mState != UserState.STATE_STOPPING
+                    && uss.mState != UserState.STATE_SHUTDOWN) {
+                num++;
+            }
+        }
+        mStartedUserArray = new int[num];
+        num = 0;
+        for (int i = 0; i < mStartedUsers.size(); i++) {
+            UserState uss = mStartedUsers.valueAt(i);
+            if (uss.mState != UserState.STATE_STOPPING
+                    && uss.mState != UserState.STATE_SHUTDOWN) {
+                mStartedUserArray[num] = mStartedUsers.keyAt(i);
+                num++;
+            }
+        }
+    }
+
+    void sendBootCompletedLocked(IIntentReceiver resultTo) {
+        for (int i = 0; i < mStartedUsers.size(); i++) {
+            UserState uss = mStartedUsers.valueAt(i);
+            if (uss.mState == UserState.STATE_BOOTING) {
+                uss.mState = UserState.STATE_RUNNING;
+                final int userId = mStartedUsers.keyAt(i);
+                Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
+                intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
+                intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
+                mService.broadcastIntentLocked(null, null, intent, null,
+                        resultTo, 0, null, null,
+                        new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
+                        AppOpsManager.OP_NONE, null, true, false,
+                        ActivityManagerService.MY_PID, Process.SYSTEM_UID, userId);
+            }
+        }
+    }
+
+    /**
+     * Refreshes the list of users related to the current user when either a
+     * user switch happens or when a new related user is started in the
+     * background.
+     */
+    void updateCurrentProfileIdsLocked() {
+        final List<UserInfo> profiles = getUserManagerLocked().getProfiles(mCurrentUserId,
+                false /* enabledOnly */);
+        int[] currentProfileIds = new int[profiles.size()]; // profiles will not be null
+        for (int i = 0; i < currentProfileIds.length; i++) {
+            currentProfileIds[i] = profiles.get(i).id;
+        }
+        mCurrentProfileIds = currentProfileIds;
+
+        synchronized (mUserProfileGroupIdsSelfLocked) {
+            mUserProfileGroupIdsSelfLocked.clear();
+            final List<UserInfo> users = getUserManagerLocked().getUsers(false);
+            for (int i = 0; i < users.size(); i++) {
+                UserInfo user = users.get(i);
+                if (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID) {
+                    mUserProfileGroupIdsSelfLocked.put(user.id, user.profileGroupId);
+                }
+            }
+        }
+    }
+
+    int[] getStartedUserArrayLocked() {
+        return mStartedUserArray;
+    }
+
+    UserInfo getCurrentUser() {
+        if ((mService.checkCallingPermission(INTERACT_ACROSS_USERS)
+                != PackageManager.PERMISSION_GRANTED) && (
+                mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
+                        != PackageManager.PERMISSION_GRANTED)) {
+            String msg = "Permission Denial: getCurrentUser() from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " requires " + INTERACT_ACROSS_USERS;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+        synchronized (mService) {
+            return getCurrentUserLocked();
+        }
+    }
+
+    UserInfo getCurrentUserLocked() {
+        int userId = mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
+        return getUserManagerLocked().getUserInfo(userId);
+    }
+
+    int getCurrentUserIdLocked() {
+        return mTargetUserId != UserHandle.USER_NULL ? mTargetUserId : mCurrentUserId;
+    }
+
+    boolean isSameProfileGroup(int callingUserId, int targetUserId) {
+        synchronized (mUserProfileGroupIdsSelfLocked) {
+            int callingProfile = mUserProfileGroupIdsSelfLocked.get(callingUserId,
+                    UserInfo.NO_PROFILE_GROUP_ID);
+            int targetProfile = mUserProfileGroupIdsSelfLocked.get(targetUserId,
+                    UserInfo.NO_PROFILE_GROUP_ID);
+            return callingProfile != UserInfo.NO_PROFILE_GROUP_ID
+                    && callingProfile == targetProfile;
+        }
+    }
+
+    boolean isCurrentProfileLocked(int userId) {
+        return ArrayUtils.contains(mCurrentProfileIds, userId);
+    }
+
+    void dump(PrintWriter pw, boolean dumpAll) {
+        pw.println("  mStartedUsers:");
+        for (int i = 0; i < mStartedUsers.size(); i++) {
+            UserState uss = mStartedUsers.valueAt(i);
+            pw.print("    User #"); pw.print(uss.mHandle.getIdentifier());
+            pw.print(": "); uss.dump("", pw);
+        }
+        pw.print("  mStartedUserArray: [");
+        for (int i = 0; i < mStartedUserArray.length; i++) {
+            if (i > 0) pw.print(", ");
+            pw.print(mStartedUserArray[i]);
+        }
+        pw.println("]");
+        pw.print("  mUserLru: [");
+        for (int i = 0; i < mUserLru.size(); i++) {
+            if (i > 0) pw.print(", ");
+            pw.print(mUserLru.get(i));
+        }
+        pw.println("]");
+        if (dumpAll) {
+            pw.print("  mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
+        }
+        synchronized (mUserProfileGroupIdsSelfLocked) {
+            if (mUserProfileGroupIdsSelfLocked.size() > 0) {
+                pw.println("  mUserProfileGroupIds:");
+                for (int i=0; i<mUserProfileGroupIdsSelfLocked.size(); i++) {
+                    pw.print("    User #");
+                    pw.print(mUserProfileGroupIdsSelfLocked.keyAt(i));
+                    pw.print(" -> profile #");
+                    pw.println(mUserProfileGroupIdsSelfLocked.valueAt(i));
+                }
+            }
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index c4b57f1..66e731a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -109,6 +109,7 @@
 import com.android.internal.util.XmlUtils;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.pm.UserManagerService;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -279,7 +280,7 @@
         0,  // STREAM_MUSIC
         0,  // STREAM_ALARM
         0,  // STREAM_NOTIFICATION
-        1,  // STREAM_BLUETOOTH_SCO
+        0,  // STREAM_BLUETOOTH_SCO
         0,  // STREAM_SYSTEM_ENFORCED
         0,  // STREAM_DTMF
         0   // STREAM_TTS
@@ -564,6 +565,27 @@
         return "card=" + card + ";device=" + device + ";";
     }
 
+    public static final class Lifecycle extends SystemService {
+        private AudioService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+            mService = new AudioService(context);
+        }
+
+        @Override
+        public void onStart() {
+            publishBinderService(Context.AUDIO_SERVICE, mService);
+        }
+
+        @Override
+        public void onBootPhase(int phase) {
+            if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+                mService.systemReady();
+            }
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // Construction
     ///////////////////////////////////////////////////////////////////////////
@@ -781,7 +803,8 @@
         int numStreamTypes = AudioSystem.getNumStreamTypes();
         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
             VolumeStreamState streamState = mStreamStates[streamType];
-            AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
+            AudioSystem.initStreamVolume(
+                streamType, streamState.mIndexMin / 10, streamState.mIndexMax / 10);
 
             streamState.applyAllVolumes();
         }
diff --git a/services/core/java/com/android/server/input/InputWindowHandle.java b/services/core/java/com/android/server/input/InputWindowHandle.java
index 9149fcc..207c05d 100644
--- a/services/core/java/com/android/server/input/InputWindowHandle.java
+++ b/services/core/java/com/android/server/input/InputWindowHandle.java
@@ -100,6 +100,17 @@
     }
 
     @Override
+    public String toString() {
+        return new StringBuilder(name)
+                .append(", layer=").append(layer)
+                .append(", frame=[").append(frameLeft).append(",").append(frameTop).append(",")
+                        .append(frameRight).append(",").append(frameBottom).append("]")
+                .append(", touchableRegion=").append(touchableRegion)
+                .toString();
+
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
             nativeDispose();
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 19d8538..9441d88 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -17,6 +17,7 @@
 package com.android.server.notification;
 
 import android.content.ComponentName;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Handler;
@@ -29,6 +30,7 @@
 import android.service.notification.ConditionProviderService;
 import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -79,7 +81,7 @@
         final Config c = new Config();
         c.caption = "condition provider";
         c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
-        c.secureSettingName = Settings.Secure.ENABLED_CONDITION_PROVIDERS;
+        c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
         c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
         c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
         c.clientLabel = R.string.condition_provider_service_binding_label;
@@ -280,6 +282,26 @@
         }
     }
 
+    @Override
+    protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+            int userId) {
+        final ContentResolver cr = mContext.getContentResolver();
+        String settingValue = Settings.Secure.getStringForUser(
+                cr,
+                settingName,
+                userId);
+        if (TextUtils.isEmpty(settingValue))
+            return null;
+        String[] packages = settingValue.split(ENABLED_SERVICES_SEPARATOR);
+        ArraySet<ComponentName> result = new ArraySet<>(packages.length);
+        for (int i = 0; i < packages.length; i++) {
+            if (!TextUtils.isEmpty(packages[i])) {
+                result.addAll(queryPackageForServices(packages[i], userId));
+            }
+        }
+        return result;
+    }
+
     public boolean subscribeIfNecessary(ComponentName component, Uri conditionId) {
         synchronized (mMutex) {
             final ConditionRecord r = getRecordLocked(conditionId, component, false /*create*/);
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index a54a61a..c7551c50 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -70,7 +70,7 @@
     protected final String TAG = getClass().getSimpleName();
     protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final String ENABLED_SERVICES_SEPARATOR = ":";
+    protected static final String ENABLED_SERVICES_SEPARATOR = ":";
 
     protected final Context mContext;
     protected final Object mMutex;
@@ -279,7 +279,8 @@
     }
 
 
-    private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName, int userId) {
+    protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+            int userId) {
         final ContentResolver cr = mContext.getContentResolver();
         String settingValue = Settings.Secure.getStringForUser(
                 cr,
@@ -319,7 +320,6 @@
                 userId);
     }
 
-
     /**
      * Remove access for any services that no longer exist.
      */
@@ -332,6 +332,38 @@
         rebuildRestoredPackages();
     }
 
+    protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
+        Set<ComponentName> installed = new ArraySet<>();
+        final PackageManager pm = mContext.getPackageManager();
+        Intent queryIntent = new Intent(mConfig.serviceInterface);
+        if (!TextUtils.isEmpty(packageName)) {
+            queryIntent.setPackage(packageName);
+        }
+        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
+                queryIntent,
+                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
+                userId);
+        if (DEBUG)
+            Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
+        if (installedServices != null) {
+            for (int i = 0, count = installedServices.size(); i < count; i++) {
+                ResolveInfo resolveInfo = installedServices.get(i);
+                ServiceInfo info = resolveInfo.serviceInfo;
+
+                ComponentName component = new ComponentName(info.packageName, info.name);
+                if (!mConfig.bindPermission.equals(info.permission)) {
+                    Slog.w(TAG, "Skipping " + getCaption() + " service "
+                            + info.packageName + "/" + info.name
+                            + ": it does not require the permission "
+                            + mConfig.bindPermission);
+                    continue;
+                }
+                installed.add(component);
+            }
+        }
+        return installed;
+    }
+
     private void updateSettingsAccordingToInstalledServices(int userId) {
         boolean restoredChanged = false;
         boolean currentChanged = false;
@@ -339,30 +371,8 @@
                 loadComponentNamesFromSetting(restoredSettingName(mConfig), userId);
         Set<ComponentName> current =
                 loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
-        Set<ComponentName> installed = new ArraySet<>();
-
-        final PackageManager pm = mContext.getPackageManager();
-        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
-                new Intent(mConfig.serviceInterface),
-                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
-                userId);
-        if (DEBUG)
-            Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
-
-        for (int i = 0, count = installedServices.size(); i < count; i++) {
-            ResolveInfo resolveInfo = installedServices.get(i);
-            ServiceInfo info = resolveInfo.serviceInfo;
-
-            ComponentName component = new ComponentName(info.packageName, info.name);
-            if (!mConfig.bindPermission.equals(info.permission)) {
-                Slog.w(TAG, "Skipping " + getCaption() + " service "
-                        + info.packageName + "/" + info.name
-                        + ": it does not require the permission "
-                        + mConfig.bindPermission);
-                continue;
-            }
-            installed.add(component);
-        }
+        // Load all services for all packages.
+        Set<ComponentName> installed = queryPackageForServices(null, userId);
 
         ArraySet<ComponentName> retained = new ArraySet<>();
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index e8e46ef..b84811f 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1579,12 +1579,6 @@
         }
 
         @Override
-        public boolean setZenModeConfig(ZenModeConfig config, String reason) {
-            checkCallerIsSystem();
-            return mZenModeHelper.setConfig(config, reason);
-        }
-
-        @Override
         public void setZenMode(int mode, Uri conditionId, String reason) throws RemoteException {
             enforceSystemOrSystemUIOrVolume("INotificationManager.setZenMode");
             final long identity = Binder.clearCallingIdentity();
@@ -1669,12 +1663,6 @@
             });
         }
 
-        @Override
-        public void requestZenModeConditions(IConditionListener callback, int relevance) {
-            enforceSystemOrSystemUIOrVolume("INotificationManager.requestZenModeConditions");
-            mZenModeHelper.requestZenModeConditions(callback, relevance);
-        }
-
         private void enforceSystemOrSystemUIOrVolume(String message) {
             if (mAudioManagerInternal != null) {
                 final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
@@ -2146,13 +2134,6 @@
                     + " id=" + id + " notification=" + notification);
         }
 
-        if (notification.getSmallIcon() != null) {
-            if (!notification.isValid()) {
-                throw new IllegalArgumentException("Invalid notification (): pkg=" + pkg
-                        + " id=" + id + " notification=" + notification);
-            }
-        }
-
         mHandler.post(new Runnable() {
             @Override
             public void run() {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 76c6443..a1f8c41 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -121,8 +121,11 @@
 
     public boolean matchesCallFilter(UserHandle userHandle, Bundle extras,
             ValidateNotificationPeople validator, int contactsTimeoutMs, float timeoutAffinity) {
-        return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle, extras,
-                validator, contactsTimeoutMs, timeoutAffinity);
+        synchronized (mConfig) {
+            return ZenModeFiltering.matchesCallFilter(mContext, mZenMode, mConfig, userHandle,
+                    extras,
+                    validator, contactsTimeoutMs, timeoutAffinity);
+        }
     }
 
     public boolean isCall(NotificationRecord record) {
@@ -130,7 +133,9 @@
     }
 
     public boolean shouldIntercept(NotificationRecord record) {
-        return mFiltering.shouldIntercept(mZenMode, mConfig, record);
+        synchronized (mConfig) {
+            return mFiltering.shouldIntercept(mZenMode, mConfig, record);
+        }
     }
 
     public void addCallback(Callback callback) {
@@ -175,10 +180,6 @@
         mConfigs.remove(user);
     }
 
-    public void requestZenModeConditions(IConditionListener callback, int relevance) {
-        mConditions.requestConditions(callback, relevance);
-    }
-
     public int getZenModeListenerInterruptionFilter() {
         return NotificationManager.zenModeToInterruptionFilter(mZenMode);
     }
@@ -203,18 +204,23 @@
 
     public List<AutomaticZenRule> getAutomaticZenRules() {
         List<AutomaticZenRule> rules = new ArrayList<>();
-        if (mConfig == null) return rules;
-        for(ZenRule rule : mConfig.automaticRules.values()) {
-            if (canManageAutomaticZenRule(rule)) {
-                rules.add(createAutomaticZenRule(rule));
+        synchronized (mConfig) {
+            if (mConfig == null) return rules;
+            for (ZenRule rule : mConfig.automaticRules.values()) {
+                if (canManageAutomaticZenRule(rule)) {
+                    rules.add(createAutomaticZenRule(rule));
+                }
             }
         }
         return rules;
     }
 
     public AutomaticZenRule getAutomaticZenRule(String id) {
-        if (mConfig == null) return null;
-        ZenRule rule = mConfig.automaticRules.get(id);
+        ZenRule rule;
+        synchronized (mConfig) {
+            if (mConfig == null) return null;
+             rule = mConfig.automaticRules.get(id);
+        }
         if (rule == null) return null;
         if (canManageAutomaticZenRule(rule)) {
              return createAutomaticZenRule(rule);
@@ -223,14 +229,18 @@
     }
 
     public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
-        if (mConfig == null) return null;
-        if (DEBUG) {
-          Log.d(TAG, "addAutomaticZenRule zenRule= " + automaticZenRule + " reason=" +reason);
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return null;
+            if (DEBUG) {
+                Log.d(TAG,
+                        "addAutomaticZenRule zenRule= " + automaticZenRule + " reason=" + reason);
+            }
+            if (!TextUtils.isEmpty(automaticZenRule.getId())) {
+                throw new IllegalArgumentException("Rule already exists");
+            }
+            newConfig = mConfig.copy();
         }
-        if (!TextUtils.isEmpty(automaticZenRule.getId())) {
-            throw new IllegalArgumentException("Rule already exists");
-        }
-        final ZenModeConfig newConfig = mConfig.copy();
         ZenRule rule = new ZenRule();
         populateZenRule(automaticZenRule, rule, true);
         newConfig.automaticRules.put(rule.id, rule);
@@ -242,12 +252,15 @@
     }
 
     public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
-        if (mConfig == null) return false;
-        if (DEBUG) {
-            Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
-                    + " reason=" + reason);
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return false;
+            if (DEBUG) {
+                Log.d(TAG, "updateAutomaticZenRule zenRule=" + automaticZenRule
+                        + " reason=" + reason);
+            }
+            newConfig = mConfig.copy();
         }
-        final ZenModeConfig newConfig = mConfig.copy();
         final String ruleId = automaticZenRule.getId();
         ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
         if (ruleId == null) {
@@ -265,8 +278,11 @@
     }
 
     public boolean removeAutomaticZenRule(String id, String reason) {
-        if (mConfig == null) return false;
-        final ZenModeConfig newConfig = mConfig.copy();
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return false;
+            newConfig = mConfig.copy();
+        }
         ZenRule rule = newConfig.automaticRules.get(id);
         if (rule == null) return false;
         if (canManageAutomaticZenRule(rule)) {
@@ -328,12 +344,15 @@
 
     private void setManualZenMode(int zenMode, Uri conditionId, String reason,
             boolean setRingerMode) {
-        if (mConfig == null) return;
-        if (!Global.isValidZenMode(zenMode)) return;
-        if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
-                + " conditionId=" + conditionId + " reason=" + reason
-                + " setRingerMode=" + setRingerMode);
-        final ZenModeConfig newConfig = mConfig.copy();
+        ZenModeConfig newConfig;
+        synchronized (mConfig) {
+            if (mConfig == null) return;
+            if (!Global.isValidZenMode(zenMode)) return;
+            if (DEBUG) Log.d(TAG, "setManualZenMode " + Global.zenModeToString(zenMode)
+                    + " conditionId=" + conditionId + " reason=" + reason
+                    + " setRingerMode=" + setRingerMode);
+            newConfig = mConfig.copy();
+        }
         if (zenMode == Global.ZEN_MODE_OFF) {
             newConfig.manualRule = null;
             for (ZenRule automaticRule : newConfig.automaticRules.values()) {
@@ -360,7 +379,9 @@
             dump(pw, prefix, "mConfigs[u=" + mConfigs.keyAt(i) + "]", mConfigs.valueAt(i));
         }
         pw.print(prefix); pw.print("mUser="); pw.println(mUser);
-        dump(pw, prefix, "mConfig", mConfig);
+        synchronized (mConfig) {
+            dump(pw, prefix, "mConfig", mConfig);
+        }
         pw.print(prefix); pw.print("mEffectsSuppressed="); pw.println(mEffectsSuppressed);
         mFiltering.dump(pw, prefix);
         mConditions.dump(pw, prefix);
@@ -437,7 +458,9 @@
     }
 
     public ZenModeConfig getConfig() {
-        return mConfig;
+        synchronized (mConfig) {
+            return mConfig.copy();
+        }
     }
 
     public boolean setConfig(ZenModeConfig config, String reason) {
@@ -462,19 +485,21 @@
                 return true;
             }
             mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
-            mConfigs.put(config.user, config);
-            if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
-            ZenLog.traceConfig(reason, mConfig, config);
-            final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
-                    getNotificationPolicy(config));
-            mConfig = config;
-            if (config.equals(mConfig)) {
-                dispatchOnConfigChanged();
+            synchronized (mConfig) {
+                mConfigs.put(config.user, config);
+                if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
+                ZenLog.traceConfig(reason, mConfig, config);
+                final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
+                        getNotificationPolicy(config));
+                mConfig = config;
+                if (config.equals(mConfig)) {
+                    dispatchOnConfigChanged();
+                }
+                if (policyChanged) {
+                    dispatchOnPolicyChanged();
+                }
             }
-            if (policyChanged){
-                dispatchOnPolicyChanged();
-            }
-            final String val = Integer.toString(mConfig.hashCode());
+            final String val = Integer.toString(config.hashCode());
             Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
             if (!evaluateZenMode(reason, setRingerMode)) {
                 applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
@@ -529,17 +554,19 @@
     }
 
     private int computeZenMode() {
-        if (mConfig == null) return Global.ZEN_MODE_OFF;
-        if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
-        int zen = Global.ZEN_MODE_OFF;
-        for (ZenRule automaticRule : mConfig.automaticRules.values()) {
-            if (automaticRule.isAutomaticActive()) {
-                if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
-                    zen = automaticRule.zenMode;
+        synchronized (mConfig) {
+            if (mConfig == null) return Global.ZEN_MODE_OFF;
+            if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
+            int zen = Global.ZEN_MODE_OFF;
+            for (ZenRule automaticRule : mConfig.automaticRules.values()) {
+                if (automaticRule.isAutomaticActive()) {
+                    if (zenSeverity(automaticRule.zenMode) > zenSeverity(zen)) {
+                        zen = automaticRule.zenMode;
+                    }
                 }
             }
+            return zen;
         }
-        return zen;
     }
 
     private void applyRestrictions() {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b3e7f5f..22bedc3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1753,11 +1753,21 @@
 
         PermissionsState permissionsState = sb.getPermissionsState();
 
-        for (String permission : pkg.requestedPermissions) {
-            BasePermission bp = mSettings.mPermissions.get(permission);
-            if (bp != null && bp.isRuntime() && (grantedPermissions == null
-                    || ArrayUtils.contains(grantedPermissions, permission))) {
-                permissionsState.grantRuntimePermission(bp, userId);
+        final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
+                | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
+
+        synchronized (mPackages) {
+            for (String permission : pkg.requestedPermissions) {
+                BasePermission bp = mSettings.mPermissions.get(permission);
+                if (bp != null && (bp.isRuntime() || bp.isDevelopment())
+                        && (grantedPermissions == null
+                               || ArrayUtils.contains(grantedPermissions, permission))) {
+                    final int flags = permissionsState.getPermissionFlags(permission, userId);
+                    // Installer cannot change immutable permissions.
+                    if ((flags & immutableFlags) == 0) {
+                        grantRuntimePermission(pkg.packageName, permission, userId);
+                    }
+                }
             }
         }
     }
@@ -2276,7 +2286,7 @@
                         mSettings.enableSystemPackageLPw(packageName);
 
                         try {
-                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, UserHandle.SYSTEM);
+                            scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
                         } catch (PackageManagerException e) {
                             Slog.e(TAG, "Failed to parse original system package: "
                                     + e.getMessage());
@@ -2772,25 +2782,38 @@
 
     @Override
     public int getPackageUid(String packageName, int userId) {
+        return getPackageUidEtc(packageName, 0, userId);
+    }
+
+    @Override
+    public int getPackageUidEtc(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return -1;
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
 
         // reader
         synchronized (mPackages) {
-            PackageParser.Package p = mPackages.get(packageName);
-            if(p != null) {
+            final PackageParser.Package p = mPackages.get(packageName);
+            if (p != null) {
                 return UserHandle.getUid(userId, p.applicationInfo.uid);
             }
-            PackageSetting ps = mSettings.mPackages.get(packageName);
-            if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) {
-                return -1;
+            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps != null) {
+                    return UserHandle.getUid(userId, ps.appId);
+                }
             }
-            return UserHandle.getUid(userId, ps.pkg.applicationInfo.uid);
         }
+
+        return -1;
     }
 
     @Override
-    public int[] getPackageGids(String packageName, int userId) throws RemoteException {
+    public int[] getPackageGids(String packageName, int userId) {
+        return getPackageGidsEtc(packageName, 0, userId);
+    }
+
+    @Override
+    public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) {
             return null;
         }
@@ -2800,14 +2823,17 @@
 
         // reader
         synchronized (mPackages) {
-            PackageParser.Package p = mPackages.get(packageName);
-            if (DEBUG_PACKAGE_INFO) {
-                Log.v(TAG, "getPackageGids" + packageName + ": " + p);
-            }
+            final PackageParser.Package p = mPackages.get(packageName);
             if (p != null) {
                 PackageSetting ps = (PackageSetting) p.mExtras;
                 return ps.getPermissionsState().computeGids(userId);
             }
+            if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) {
+                final PackageSetting ps = mSettings.mPackages.get(packageName);
+                if (ps != null) {
+                    return ps.getPermissionsState().computeGids(userId);
+                }
+            }
         }
 
         return null;
@@ -3558,7 +3584,8 @@
                             killUid(appId, userId, KILL_APP_REASON_GIDS_CHANGED);
                         }
                     });
-                } break;
+                }
+                break;
             }
 
             mOnPermissionChangeListeners.onPermissionsChanged(uid);
@@ -5685,7 +5712,7 @@
             }
             try {
                 scanPackageTracedLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
-                        scanFlags, currentTime, UserHandle.SYSTEM);
+                        scanFlags, currentTime, null);
             } catch (PackageManagerException e) {
                 Slog.w(TAG, "Failed to parse " + file + ": " + e.getMessage());
 
@@ -5791,8 +5818,6 @@
      */
     private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
             long currentTime, UserHandle user) throws PackageManagerException {
-        Preconditions.checkNotNull(user);
-
         if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile);
         parseFlags |= mDefParseFlags;
         PackageParser pp = new PackageParser();
@@ -12141,7 +12166,7 @@
                 int oldScanFlags = SCAN_UPDATE_SIGNATURE | SCAN_UPDATE_TIME;
                 try {
                     scanPackageTracedLI(restoreFile, oldParseFlags, oldScanFlags, origUpdateTime,
-                            UserHandle.SYSTEM);
+                            null);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "Failed to restore package : " + pkgName + " after failed upgrade: "
                             + e.getMessage());
@@ -13276,8 +13301,7 @@
 
         final PackageParser.Package newPkg;
         try {
-            newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0,
-                    UserHandle.SYSTEM);
+            newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null);
         } catch (PackageManagerException e) {
             Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage());
             return false;
@@ -15841,8 +15865,7 @@
                 synchronized (mInstallLock) {
                     PackageParser.Package pkg = null;
                     try {
-                        pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0,
-                                UserHandle.SYSTEM);
+                        pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, null);
                     } catch (PackageManagerException e) {
                         Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
                     }
@@ -16005,8 +16028,7 @@
             synchronized (mInstallLock) {
                 final PackageParser.Package pkg;
                 try {
-                    pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0,
-                            UserHandle.SYSTEM);
+                    pkg = scanPackageTracedLI(ps.codePath, parseFlags, SCAN_INITIAL, 0, null);
                     loaded.add(pkg.applicationInfo);
                 } catch (PackageManagerException e) {
                     Slog.w(TAG, "Failed to scan " + ps.codePath + ": " + e.getMessage());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index bf960a7..5d0e83d 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,14 +16,15 @@
 
 package com.android.server.pm;
 
-import android.accounts.Account;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.IStopUserCallback;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -47,6 +48,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.system.ErrnoException;
@@ -60,9 +62,11 @@
 import android.util.TimeUtils;
 import android.util.Xml;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
@@ -84,11 +88,18 @@
 
 import libcore.io.IoUtils;
 
+/**
+ * Service for {@link UserManager}.
+ *
+ * Method naming convention:
+ * - Methods suffixed with "Locked" should be called within the {@code this} lock.
+ * - Methods suffixed with "RL" should be called within the {@link #mRestrictionsLock} lock.
+ */
 public class UserManagerService extends IUserManager.Stub {
 
     private static final String LOG_TAG = "UserManagerService";
 
-    private static final boolean DBG = false;
+    private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
 
     private static final String TAG_NAME = "name";
     private static final String ATTR_FLAGS = "flags";
@@ -156,7 +167,38 @@
     private final File mUserListFile;
 
     private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
-    private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>();
+
+    private final Object mRestrictionsLock = new Object();
+
+    /**
+     * User restrictions set via UserManager.  This doesn't include restrictions set by
+     * device owner / profile owners.
+     *
+     * DO NOT Change existing {@link Bundle} in it.  When changing a restriction for a user,
+     * a new {@link Bundle} should always be created and set.  This is because a {@link Bundle}
+     * maybe shared between {@link #mBaseUserRestrictions} and
+     * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately.
+     * (Otherwise we won't be able to detect what restrictions have changed in
+     * {@link #updateUserRestrictionsInternalRL).
+     */
+    @GuardedBy("mRestrictionsLock")
+    private final SparseArray<Bundle> mBaseUserRestrictions = new SparseArray<>();
+
+    /**
+     * Cached user restrictions that are in effect -- i.e. {@link #mBaseUserRestrictions} combined
+     * with device / profile owner restrictions.  We'll initialize it lazily; use
+     * {@link #getEffectiveUserRestrictions} to access it.
+     *
+     * DO NOT Change existing {@link Bundle} in it.  When changing a restriction for a user,
+     * a new {@link Bundle} should always be created and set.  This is because a {@link Bundle}
+     * maybe shared between {@link #mBaseUserRestrictions} and
+     * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately.
+     * (Otherwise we won't be able to detect what restrictions have changed in
+     * {@link #updateUserRestrictionsInternalRL).
+     */
+    @GuardedBy("mRestrictionsLock")
+    private final SparseArray<Bundle> mCachedEffectiveUserRestrictions = new SparseArray<>();
+
     private final Bundle mGuestRestrictions = new Bundle();
 
     /**
@@ -172,6 +214,8 @@
 
     private IAppOpsService mAppOpsService;
 
+    private final LocalService mLocalService;
+
     private static UserManagerService sInstance;
 
     public static UserManagerService getInstance() {
@@ -227,6 +271,8 @@
                 sInstance = this;
             }
         }
+        mLocalService = new LocalService();
+        LocalServices.addService(UserManagerInternal.class, mLocalService);
     }
 
     void systemReady() {
@@ -254,8 +300,9 @@
         mAppOpsService = IAppOpsService.Stub.asInterface(
                 ServiceManager.getService(Context.APP_OPS_SERVICE));
         for (int i = 0; i < mUserIds.length; ++i) {
+            final int userId = mUserIds[i];
             try {
-                mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]);
+                mAppOpsService.setUserRestrictions(getEffectiveUserRestrictions(userId), userId);
             } catch (RemoteException e) {
                 Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
             }
@@ -584,75 +631,171 @@
         }
     }
 
-    @Override
-    public boolean hasUserRestriction(String restrictionKey, int userId) {
-        synchronized (mPackagesLock) {
-            Bundle restrictions = mUserRestrictions.get(userId);
-            return restrictions != null && restrictions.getBoolean(restrictionKey);
+    @GuardedBy("mRestrictionsLock")
+    private Bundle computeEffectiveUserRestrictionsRL(int userId) {
+        final DevicePolicyManagerInternal dpmi =
+                LocalServices.getService(DevicePolicyManagerInternal.class);
+        final Bundle systemRestrictions = mBaseUserRestrictions.get(userId);
+
+        final Bundle effective;
+        if (dpmi == null) {
+            // TODO Make sure it's because DPMS is disabled and not because we called it too early.
+            effective = systemRestrictions;
+        } else {
+            effective = dpmi.getComposedUserRestrictions(userId, systemRestrictions);
+        }
+        return effective;
+    }
+
+    @GuardedBy("mRestrictionsLock")
+    private void invalidateEffectiveUserRestrictionsRL(int userId) {
+        if (DBG) {
+            Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId);
+        }
+        mCachedEffectiveUserRestrictions.remove(userId);
+    }
+
+    private Bundle getEffectiveUserRestrictions(int userId) {
+        synchronized (mRestrictionsLock) {
+            Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId);
+            if (restrictions == null) {
+                restrictions = computeEffectiveUserRestrictionsRL(userId);
+                mCachedEffectiveUserRestrictions.put(userId, restrictions);
+            }
+            return restrictions;
         }
     }
 
+    /** @return a specific user restriction that's in effect currently. */
+    @Override
+    public boolean hasUserRestriction(String restrictionKey, int userId) {
+        Bundle restrictions = getEffectiveUserRestrictions(userId);
+        return restrictions != null && restrictions.getBoolean(restrictionKey);
+    }
+
+    /**
+     * @return UserRestrictions that are in effect currently.  This always returns a new
+     * {@link Bundle}.
+     */
     @Override
     public Bundle getUserRestrictions(int userId) {
-        synchronized (mPackagesLock) {
-            Bundle restrictions = mUserRestrictions.get(userId);
-            return restrictions != null ? new Bundle(restrictions) : new Bundle();
-        }
+        Bundle restrictions = getEffectiveUserRestrictions(userId);
+        return restrictions != null ? new Bundle(restrictions) : new Bundle();
     }
 
     @Override
     public void setUserRestriction(String key, boolean value, int userId) {
         checkManageUsersPermission("setUserRestriction");
-        synchronized (mPackagesLock) {
-            if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) {
-                Bundle restrictions = getUserRestrictions(userId);
-                restrictions.putBoolean(key, value);
-                setUserRestrictionsInternalLocked(restrictions, userId);
-            }
+        if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) {
+            setUserRestrictionNoCheck(key, value, userId);
         }
     }
 
     @Override
     public void setSystemControlledUserRestriction(String key, boolean value, int userId) {
         checkSystemOrRoot("setSystemControlledUserRestriction");
-        synchronized (mPackagesLock) {
-            Bundle restrictions = getUserRestrictions(userId);
-            restrictions.putBoolean(key, value);
-            setUserRestrictionsInternalLocked(restrictions, userId);
+        setUserRestrictionNoCheck(key, value, userId);
+    }
+
+    private void setUserRestrictionNoCheck(String key, boolean value, int userId) {
+        synchronized (mRestrictionsLock) {
+            // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
+            // a copy.
+            final Bundle newRestrictions = new Bundle();
+            UserRestrictionsUtils.merge(newRestrictions, mBaseUserRestrictions.get(userId));
+            newRestrictions.putBoolean(key, value);
+
+            updateUserRestrictionsInternalRL(newRestrictions, userId);
         }
     }
 
-    @Override
-    public void setUserRestrictions(Bundle restrictions, int userId) {
-        checkManageUsersPermission("setUserRestrictions");
-        if (restrictions == null) return;
-
-        synchronized (mPackagesLock) {
-            final Bundle oldUserRestrictions = mUserRestrictions.get(userId);
-            // Restore the original state of system controlled restrictions from oldUserRestrictions
-            for (String key : UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS) {
-                restrictions.remove(key);
-                if (oldUserRestrictions.containsKey(key)) {
-                    restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key));
-                }
-            }
-            setUserRestrictionsInternalLocked(restrictions, userId);
+    /**
+     * Optionally updating user restrictions, calculate the effective user restrictions by
+     * consulting {@link com.android.server.devicepolicy.DevicePolicyManagerService} and also
+     * apply it to {@link com.android.server.AppOpsService}.
+     * TODO applyUserRestrictionsLocked() should also apply to system settings.
+     *
+     * @param newRestrictions User restrictions to set.  If null, only the effective restrictions
+     *     will be updated.  Note don't pass an existing Bundle in {@link #mBaseUserRestrictions}
+     *     or {@link #mCachedEffectiveUserRestrictions}; that'll most likely cause a sub
+     * @param userId target user ID.
+     */
+    @GuardedBy("mRestrictionsLock")
+    private void updateUserRestrictionsInternalRL(
+            @Nullable Bundle newRestrictions, int userId) {
+        if (DBG) {
+            Log.d(LOG_TAG, "updateUserRestrictionsInternalLocked userId=" + userId
+                    + " bundle=" + newRestrictions);
         }
+        final Bundle prevRestrictions = getEffectiveUserRestrictions(userId);
+
+        // Update system restrictions.
+        if (newRestrictions != null) {
+            // If newRestrictions == the current one, it's probably a bug.
+            Preconditions.checkState(mBaseUserRestrictions.get(userId) != newRestrictions);
+            Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId)
+                    != newRestrictions);
+            mBaseUserRestrictions.put(userId, newRestrictions);
+        }
+
+        mCachedEffectiveUserRestrictions.put(
+                userId, computeEffectiveUserRestrictionsRL(userId));
+
+        applyUserRestrictionsRL(userId, mBaseUserRestrictions.get(userId), prevRestrictions);
     }
 
-    private void setUserRestrictionsInternalLocked(Bundle restrictions, int userId) {
-        final Bundle userRestrictions = mUserRestrictions.get(userId);
-        userRestrictions.clear();
-        userRestrictions.putAll(restrictions);
-        long token = Binder.clearCallingIdentity();
+    @GuardedBy("mRestrictionsLock")
+    private void applyUserRestrictionsRL(int userId,
+            Bundle newRestrictions, Bundle prevRestrictions) {
+        final long token = Binder.clearCallingIdentity();
         try {
-        mAppOpsService.setUserRestrictions(userRestrictions, userId);
+            mAppOpsService.setUserRestrictions(newRestrictions, userId);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
         } finally {
             Binder.restoreCallingIdentity(token);
         }
-        scheduleWriteUserLocked(mUsers.get(userId));
+
+        // TODO Move the code from DPMS.setUserRestriction().
+    }
+
+    @GuardedBy("mRestrictionsLock")
+    private void updateEffectiveUserRestrictionsRL(int userId) {
+        updateUserRestrictionsInternalRL(null, userId);
+    }
+
+    @GuardedBy("mRestrictionsLock")
+    private void updateEffectiveUserRestrictionsForAllUsersRL() {
+        // First, invalidate all cached values.
+        synchronized (mRestrictionsLock) {
+            mCachedEffectiveUserRestrictions.clear();
+        }
+        // We don't want to call into ActivityManagerNative while taking a lock, so we'll call
+        // it on a handler.
+        final Runnable r = new Runnable() {
+            @Override
+            public void run() {
+                // Then get the list of running users.
+                final int[] runningUsers;
+                try {
+                    runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+                } catch (RemoteException e) {
+                    Log.w(LOG_TAG, "Unable to access ActivityManagerNative");
+                    return;
+                }
+                // Then re-calculate the effective restrictions and apply, only for running users.
+                // It's okay if a new user has started after the getRunningUserIds() call,
+                // because we'll do the same thing (re-calculate the restrictions and apply)
+                // when we start a user.
+                // TODO: "Apply restrictions upon user start hasn't been implemented.  Implement it.
+                synchronized (mRestrictionsLock) {
+                    for (int i = 0; i < runningUsers.length; i++) {
+                        updateUserRestrictionsInternalRL(null, runningUsers[i]);
+                    }
+                }
+            }
+        };
+        mHandler.post(r);
     }
 
     /**
@@ -922,7 +1065,9 @@
         mUserVersion = USER_VERSION;
 
         Bundle restrictions = new Bundle();
-        mUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+        synchronized (mRestrictionsLock) {
+            mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+        }
 
         updateUserIdsLocked();
         initDefaultGuestRestrictions();
@@ -985,9 +1130,13 @@
             serializer.startTag(null, TAG_NAME);
             serializer.text(userInfo.name);
             serializer.endTag(null, TAG_NAME);
-            Bundle restrictions = mUserRestrictions.get(userInfo.id);
+            Bundle restrictions;
+            synchronized (mRestrictionsLock) {
+                restrictions = mBaseUserRestrictions.get(userInfo.id);
+            }
             if (restrictions != null) {
-                UserRestrictionsUtils.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS);
+                UserRestrictionsUtils
+                        .writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_USER);
 
@@ -1127,7 +1276,9 @@
             userInfo.guestToRemove = guestToRemove;
             userInfo.profileGroupId = profileGroupId;
             userInfo.restrictedProfileParentId = restrictedProfileParentId;
-            mUserRestrictions.append(id, restrictions);
+            synchronized (mRestrictionsLock) {
+                mBaseUserRestrictions.append(id, restrictions);
+            }
             return userInfo;
 
         } catch (IOException ioe) {
@@ -1329,7 +1480,9 @@
                     scheduleWriteUserLocked(userInfo);
                     updateUserIdsLocked();
                     Bundle restrictions = new Bundle();
-                    mUserRestrictions.append(userId, restrictions);
+                    synchronized (mRestrictionsLock) {
+                        mBaseUserRestrictions.append(userId, restrictions);
+                    }
                 }
             }
             mPm.newUserCreated(userId);
@@ -1612,25 +1765,6 @@
         }
     }
 
-    @Override
-    public void removeRestrictions() {
-        checkManageUsersPermission("remove restrictions");
-        final int userHandle = UserHandle.getCallingUserId();
-        removeRestrictionsForUser(userHandle, true);
-    }
-
-    private void removeRestrictionsForUser(final int userHandle, boolean unhideApps) {
-        synchronized (mPackagesLock) {
-            // Remove all user restrictions
-            setUserRestrictions(new Bundle(), userHandle);
-            // Remove any app restrictions
-            cleanAppRestrictions(userHandle);
-        }
-        if (unhideApps) {
-            unhideAllInstalledAppsForUser(userHandle);
-        }
-    }
-
     private void unhideAllInstalledAppsForUser(final int userHandle) {
         mHandler.post(new Runnable() {
             @Override
@@ -2058,7 +2192,10 @@
                 }
                 pw.println("    Restrictions:");
                 UserRestrictionsUtils.dumpRestrictions(
-                        pw, "      ", mUserRestrictions.get(user.id));
+                        pw, "      ", mBaseUserRestrictions.get(user.id));
+                pw.println("    Effective restrictions:");
+                UserRestrictionsUtils.dumpRestrictions(
+                        pw, "      ", mCachedEffectiveUserRestrictions.get(user.id));
             }
             pw.println();
             pw.println("Guest restrictions:");
@@ -2091,4 +2228,49 @@
     boolean isInitialized(int userId) {
         return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0;
     }
+
+    private class LocalService extends UserManagerInternal {
+
+        @Override
+        public Object getUserRestrictionsLock() {
+            return mRestrictionsLock;
+        }
+
+        @Override
+        @GuardedBy("mRestrictionsLock")
+        public void updateEffectiveUserRestrictionsRL(int userId) {
+            UserManagerService.this.updateEffectiveUserRestrictionsRL(userId);
+        }
+
+        @Override
+        @GuardedBy("mRestrictionsLock")
+        public void updateEffectiveUserRestrictionsForAllUsersRL() {
+            UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersRL();
+        }
+
+        @Override
+        public Bundle getBaseUserRestrictions(int userId) {
+            synchronized (mRestrictionsLock) {
+                return mBaseUserRestrictions.get(userId);
+            }
+        }
+
+        @Override
+        public void setBaseUserRestrictionsByDpmsForMigration(
+                int userId, Bundle baseRestrictions) {
+            synchronized (mRestrictionsLock) {
+                mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
+                invalidateEffectiveUserRestrictionsRL(userId);
+            }
+
+            synchronized (mPackagesLock) {
+                final UserInfo userInfo = mUsers.get(userId);
+                if (userInfo != null) {
+                    writeUserLocked(userInfo);
+                } else {
+                    Slog.w(LOG_TAG, "UserInfo not found for " + userId);
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index db1fd2e..23e3b35 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -86,7 +86,6 @@
             String tag) throws IOException {
         serializer.startTag(null, tag);
         for (String key : USER_RESTRICTIONS) {
-            //
             if (restrictions.getBoolean(key)
                     && !NON_PERSIST_USER_RESTRICTIONS.contains(key)) {
                 serializer.attribute(null, key, "true");
@@ -105,6 +104,17 @@
         }
     }
 
+    public static void merge(Bundle dest, Bundle in) {
+        if (in == null) {
+            return;
+        }
+        for (String key : in.keySet()) {
+            if (in.getBoolean(key, false)) {
+                dest.putBoolean(key, true);
+            }
+        }
+    }
+
     public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) {
         boolean noneSet = true;
         if (restrictions != null) {
@@ -114,9 +124,11 @@
                     noneSet = false;
                 }
             }
-        }
-        if (noneSet) {
-            pw.println(prefix + "none");
+            if (noneSet) {
+                pw.println(prefix + "none");
+            }
+        } else {
+            pw.println(prefix + "null");
         }
     }
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index e354029..b38b9ce 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3016,7 +3016,7 @@
 
         // Display task switcher for ALT-TAB.
         if (down && repeatCount == 0 && keyCode == KeyEvent.KEYCODE_TAB) {
-            if (mRecentAppsHeldModifiers == 0 && !keyguardOn) {
+            if (mRecentAppsHeldModifiers == 0 && !keyguardOn && isUserSetupComplete()) {
                 final int shiftlessModifiers = event.getModifiers() & ~KeyEvent.META_SHIFT_MASK;
                 if (KeyEvent.metaStateHasModifiers(shiftlessModifiers, KeyEvent.META_ALT_ON)) {
                     mRecentAppsHeldModifiers = shiftlessModifiers;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7abc048..468cf6d 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -64,7 +64,6 @@
 import android.view.animation.PathInterpolator;
 import android.view.animation.ScaleAnimation;
 import android.view.animation.TranslateAnimation;
-import android.view.animation.TranslateYAnimation;
 
 import com.android.internal.util.DumpUtils.Dump;
 import com.android.server.AttributeCache;
@@ -161,6 +160,7 @@
     // Used for thumbnail transitions. True if we're scaling up, false if scaling down
     private boolean mNextAppTransitionScaleUp;
     private IRemoteCallback mNextAppTransitionCallback;
+    private IRemoteCallback mAnimationFinishedCallback;
     private int mNextAppTransitionEnter;
     private int mNextAppTransitionExit;
     private int mNextAppTransitionInPlace;
@@ -175,7 +175,7 @@
     private Rect mTmpFromClipRect = new Rect();
     private Rect mTmpToClipRect = new Rect();
 
-    private final Rect mTmpStartRect = new Rect();
+    private final Rect mTmpRect = new Rect();
 
     private final static int APP_STATE_IDLE = 0;
     private final static int APP_STATE_READY = 1;
@@ -456,17 +456,19 @@
         return -startPos / denom;
     }
 
-    private Animation createScaleUpAnimationLocked(
-            int transit, boolean enter, int appWidth, int appHeight) {
-        Animation a = null;
-        getDefaultNextAppTransitionStartRect(mTmpStartRect);
+    private Animation createScaleUpAnimationLocked(int transit, boolean enter,
+            Rect containingFrame) {
+        Animation a;
+        getDefaultNextAppTransitionStartRect(mTmpRect);
+        final int appWidth = containingFrame.width();
+        final int appHeight = containingFrame.height();
         if (enter) {
             // Entering app zooms out from the center of the initial rect.
-            float scaleW = mTmpStartRect.width() / (float) appWidth;
-            float scaleH = mTmpStartRect.height() / (float) appHeight;
+            float scaleW = mTmpRect.width() / (float) appWidth;
+            float scaleH = mTmpRect.height() / (float) appHeight;
             Animation scale = new ScaleAnimation(scaleW, 1, scaleH, 1,
-                    computePivot(mTmpStartRect.left, scaleW),
-                    computePivot(mTmpStartRect.right, scaleH));
+                    computePivot(mTmpRect.left, scaleW),
+                    computePivot(mTmpRect.right, scaleH));
             scale.setInterpolator(mDecelerateInterpolator);
 
             Animation alpha = new AlphaAnimation(0, 1);
@@ -543,20 +545,20 @@
 
             final int appWidth = appFrame.width();
             final int appHeight = appFrame.height();
-            // mTmpStartRect will contain an area around the launcher icon that was pressed. We will
+            // mTmpRect will contain an area around the launcher icon that was pressed. We will
             // clip reveal from that area in the final area of the app.
-            getDefaultNextAppTransitionStartRect(mTmpStartRect);
+            getDefaultNextAppTransitionStartRect(mTmpRect);
 
             float t = 0f;
             if (appHeight > 0) {
-                t = (float) mTmpStartRect.left / appHeight;
+                t = (float) mTmpRect.left / appHeight;
             }
             int translationY = mClipRevealTranslationY + (int)(appHeight / 7f * t);
 
-            int centerX = mTmpStartRect.centerX();
-            int centerY = mTmpStartRect.centerY();
-            int halfWidth = mTmpStartRect.width() / 2;
-            int halfHeight = mTmpStartRect.height() / 2;
+            int centerX = mTmpRect.centerX();
+            int centerY = mTmpRect.centerY();
+            int halfWidth = mTmpRect.width() / 2;
+            int halfHeight = mTmpRect.height() / 2;
 
             // Clip third of the from size of launch icon, expand to full width/height
             Animation clipAnimLR = new ClipRectLRAnimation(
@@ -691,19 +693,19 @@
 
         float scaleW = appWidth / thumbWidth;
         float unscaledHeight = thumbHeight * scaleW;
-        getNextAppTransitionStartRect(taskId, mTmpStartRect);
-        float unscaledStartY = mTmpStartRect.top - (unscaledHeight - thumbHeight) / 2f;
+        getNextAppTransitionStartRect(taskId, mTmpRect);
+        float unscaledStartY = mTmpRect.top - (unscaledHeight - thumbHeight) / 2f;
         if (mNextAppTransitionScaleUp) {
             // Animation up from the thumbnail to the full screen
             Animation scale = new ScaleAnimation(1f, scaleW, 1f, scaleW,
-                    mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
+                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
             scale.setInterpolator(mTouchResponseInterpolator);
             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
             Animation alpha = new AlphaAnimation(1, 0);
             alpha.setInterpolator(mThumbnailFadeOutInterpolator);
             alpha.setDuration(THUMBNAIL_APP_TRANSITION_ALPHA_DURATION);
             final float toX = appRect.left + appRect.width() / 2 -
-                    (mTmpStartRect.left + thumbWidth / 2);
+                    (mTmpRect.left + thumbWidth / 2);
             final float toY = appRect.top + mNextAppTransitionInsets.top + -unscaledStartY;
             Animation translate = new TranslateAnimation(0, toX, 0, toY);
             translate.setInterpolator(mTouchResponseInterpolator);
@@ -718,7 +720,7 @@
         } else {
             // Animation down from the full screen to the thumbnail
             Animation scale = new ScaleAnimation(scaleW, 1f, scaleW, 1f,
-                    mTmpStartRect.left + (thumbWidth / 2f), mTmpStartRect.top + (thumbHeight / 2f));
+                    mTmpRect.left + (thumbWidth / 2f), mTmpRect.top + (thumbHeight / 2f));
             scale.setInterpolator(mTouchResponseInterpolator);
             scale.setDuration(THUMBNAIL_APP_TRANSITION_DURATION);
             Animation alpha = new AlphaAnimation(0f, 1f);
@@ -746,14 +748,15 @@
      * activity that is leaving, and the activity that is entering.
      */
     Animation createAspectScaledThumbnailEnterExitAnimationLocked(int thumbTransitState,
-            int appWidth, int appHeight, int orientation, int transit, Rect containingFrame,
-            Rect contentInsets, @Nullable Rect surfaceInsets, boolean resizedWindow,
-            int taskId) {
+            int orientation, int transit, Rect containingFrame, Rect contentInsets,
+            @Nullable Rect surfaceInsets, boolean freeform, int taskId) {
         Animation a;
-        getDefaultNextAppTransitionStartRect(mTmpStartRect);
-        final int thumbWidthI = mTmpStartRect.width();
+        final int appWidth = containingFrame.width();
+        final int appHeight = containingFrame.height();
+        getDefaultNextAppTransitionStartRect(mTmpRect);
+        final int thumbWidthI = mTmpRect.width();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
-        final int thumbHeightI = mTmpStartRect.height();
+        final int thumbHeightI = mTmpRect.height();
         final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
 
         // Used for the ENTER_SCALE_UP and EXIT_SCALE_DOWN transitions
@@ -762,8 +765,8 @@
 
         switch (thumbTransitState) {
             case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
-                if (resizedWindow) {
-                    a = createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
+                if (freeform) {
+                    a = createAspectScaledThumbnailEnterFreeformAnimationLocked(
                             containingFrame, surfaceInsets, taskId);
                 } else {
                     mTmpFromClipRect.set(containingFrame);
@@ -778,18 +781,24 @@
                         int unscaledThumbHeight = (int) (thumbHeight / scale);
                         mTmpFromClipRect.bottom = mTmpFromClipRect.top + unscaledThumbHeight;
                     } else {
-                        // In landscape, we scale the height and clip to the top/left square
-                        scale = thumbHeight / (appHeight - contentInsets.top);
+                        // In landscape, we scale the height and clip to the top/left square. We
+                        // only scale the part that is not covered by status bar and the nav bar.
+                        scale = thumbHeight / (appHeight - contentInsets.top
+                                - contentInsets.bottom);
                         scaledTopDecor = (int) (scale * contentInsets.top);
                         int unscaledThumbWidth = (int) (thumbWidth / scale);
                         mTmpFromClipRect.right = mTmpFromClipRect.left + unscaledThumbWidth;
+                        // This removes the navigation bar from the first frame, so it better
+                        // matches the thumbnail. We need to do this explicitly in landscape,
+                        // because in portrait we already crop vertically.
+                        mTmpFromClipRect.bottom = mTmpFromClipRect.bottom - contentInsets.bottom;
                     }
 
                     mNextAppTransitionInsets.set(contentInsets);
 
                     Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
-                            computePivot(mTmpStartRect.left, scale),
-                            computePivot(mTmpStartRect.top, scale));
+                            computePivot(mTmpRect.left, scale),
+                            computePivot(mTmpRect.top, scale));
                     Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
                     Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
 
@@ -825,39 +834,49 @@
             }
             case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
                 // App window scaling down from full screen
-                mTmpFromClipRect.set(containingFrame);
-                mTmpToClipRect.set(containingFrame);
-                // exclude top screen decor (status bar) region from the destination clip.
-                mTmpToClipRect.top = contentInsets.top;
-                if (orientation == Configuration.ORIENTATION_PORTRAIT) {
-                    // In portrait, we scale the width and clip to the top/left square
-                    scale = thumbWidth / appWidth;
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbHeight = (int) (thumbHeight / scale);
-                    mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
+                if (freeform) {
+                    a = createAspectScaledThumbnailExitFreeformAnimationLocked(
+                            containingFrame, surfaceInsets, taskId);
                 } else {
-                    // In landscape, we scale the height and clip to the top/left square
-                    scale = thumbHeight / (appHeight - contentInsets.top);
-                    scaledTopDecor = (int) (scale * contentInsets.top);
-                    int unscaledThumbWidth = (int) (thumbWidth / scale);
-                    mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
+                    mTmpFromClipRect.set(containingFrame);
+                    mTmpToClipRect.set(containingFrame);
+                    // exclude top screen decor (status bar) region from the destination clip.
+                    mTmpToClipRect.top = contentInsets.top;
+                    if (orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        // In portrait, we scale the width and clip to the top/left square
+                        scale = thumbWidth / appWidth;
+                        scaledTopDecor = (int) (scale * contentInsets.top);
+                        int unscaledThumbHeight = (int) (thumbHeight / scale);
+                        mTmpToClipRect.bottom = mTmpToClipRect.top + unscaledThumbHeight;
+                    } else {
+                        // In landscape, we scale the height and clip to the top/left square. We only
+                        // scale the part that is not covered by status bar and the nav bar.
+                        scale = thumbHeight / (appHeight - contentInsets.top - contentInsets.bottom);
+                        scaledTopDecor = (int) (scale * contentInsets.top);
+                        int unscaledThumbWidth = (int) (thumbWidth / scale);
+                        mTmpToClipRect.right = mTmpToClipRect.left + unscaledThumbWidth;
+                        // This removes the navigation bar from the last frame, so it better matches the
+                        // thumbnail. We need to do this explicitly in landscape, because in portrait we
+                        // already crop vertically.
+                        mTmpToClipRect.bottom = mTmpToClipRect.bottom - contentInsets.bottom;
+                    }
+
+                    mNextAppTransitionInsets.set(contentInsets);
+
+                    Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
+                            computePivot(mTmpRect.left, scale),
+                            computePivot(mTmpRect.top, scale));
+                    Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
+                    Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
+
+                    AnimationSet set = new AnimationSet(true);
+                    set.addAnimation(clipAnim);
+                    set.addAnimation(scaleAnim);
+                    set.addAnimation(translateAnim);
+
+                    a = set;
+                    a.setZAdjustment(Animation.ZORDER_TOP);
                 }
-
-                mNextAppTransitionInsets.set(contentInsets);
-
-                Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
-                        computePivot(mTmpStartRect.left, scale),
-                        computePivot(mTmpStartRect.top, scale));
-                Animation clipAnim = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-                Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
-
-                AnimationSet set = new AnimationSet(true);
-                set.addAnimation(clipAnim);
-                set.addAnimation(scaleAnim);
-                set.addAnimation(translateAnim);
-
-                a = set;
-                a.setZAdjustment(Animation.ZORDER_TOP);
                 break;
             }
             default:
@@ -870,29 +889,66 @@
                 mTouchResponseInterpolator);
     }
 
-    private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
-            Rect frame, @Nullable Rect surfaceInsets, int taskId) {
-        getNextAppTransitionStartRect(taskId, mTmpStartRect);
-        float width = frame.width();
-        float height = frame.height();
-        float scaleWidth = mTmpStartRect.width() / width;
-        float scaleHeight = mTmpStartRect.height() / height;
+    private Animation createAspectScaledThumbnailEnterFreeformAnimationLocked(Rect frame,
+            @Nullable Rect surfaceInsets, int taskId) {
+        getNextAppTransitionStartRect(taskId, mTmpRect);
+        return createAspectScaledThumbnailFreeformAnimationLocked(mTmpRect, frame, surfaceInsets,
+                true);
+    }
+
+    private Animation createAspectScaledThumbnailExitFreeformAnimationLocked(Rect frame,
+            @Nullable Rect surfaceInsets, int taskId) {
+        getNextAppTransitionStartRect(taskId, mTmpRect);
+        return createAspectScaledThumbnailFreeformAnimationLocked(frame, mTmpRect, surfaceInsets,
+                false);
+    }
+
+    private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
+            Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
+        final float sourceWidth = sourceFrame.width();
+        final float sourceHeight = sourceFrame.height();
+        final float destWidth = destFrame.width();
+        final float destHeight = destFrame.height();
+        final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
+        final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
         AnimationSet set = new AnimationSet(true);
-        int surfaceInsetsHorizontal = surfaceInsets == null
+        final int surfaceInsetsH = surfaceInsets == null
                 ? 0 : surfaceInsets.left + surfaceInsets.right;
-        int surfaceInsetsVertical = surfaceInsets == null
+        final int surfaceInsetsV = surfaceInsets == null
                 ? 0 : surfaceInsets.top + surfaceInsets.bottom;
         // We want the scaling to happen from the center of the surface. In order to achieve that,
         // we need to account for surface insets that will be used to enlarge the surface.
-        ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
-                (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
-        int fromX = mTmpStartRect.left + mTmpStartRect.width() / 2
-                - (frame.left + frame.width() / 2);
-        int fromY = mTmpStartRect.top + mTmpStartRect.height() / 2
-                - (frame.top + frame.height() / 2);
-        TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
+        final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
+        final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
+        final ScaleAnimation scale = enter ?
+                new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
+                : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
+        final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
+        final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
+        final int destHCenter = destFrame.left + destFrame.width() / 2;
+        final int destVCenter = destFrame.top + destFrame.height() / 2;
+        final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
+        final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
+        final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
+                : new TranslateAnimation(0, fromX, 0, fromY);
         set.addAnimation(scale);
         set.addAnimation(translation);
+
+        final IRemoteCallback callback = mAnimationFinishedCallback;
+        if (callback != null) {
+            set.setAnimationListener(new Animation.AnimationListener() {
+                @Override
+                public void onAnimationStart(Animation animation) { }
+
+                @Override
+                public void onAnimationEnd(Animation animation) {
+                    mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
+                }
+
+                @Override
+                public void onAnimationRepeat(Animation animation) { }
+            });
+        }
         return set;
     }
 
@@ -903,7 +959,7 @@
     Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit,
             Bitmap thumbnailHeader) {
         Animation a;
-        getDefaultNextAppTransitionStartRect(mTmpStartRect);
+        getDefaultNextAppTransitionStartRect(mTmpRect);
         final int thumbWidthI = thumbnailHeader.getWidth();
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = thumbnailHeader.getHeight();
@@ -914,8 +970,8 @@
             float scaleW = appWidth / thumbWidth;
             float scaleH = appHeight / thumbHeight;
             Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
-                    computePivot(mTmpStartRect.left, 1 / scaleW),
-                    computePivot(mTmpStartRect.top, 1 / scaleH));
+                    computePivot(mTmpRect.left, 1 / scaleW),
+                    computePivot(mTmpRect.top, 1 / scaleH));
             scale.setInterpolator(mDecelerateInterpolator);
 
             Animation alpha = new AlphaAnimation(1, 0);
@@ -931,8 +987,8 @@
             float scaleW = appWidth / thumbWidth;
             float scaleH = appHeight / thumbHeight;
             a = new ScaleAnimation(scaleW, 1, scaleH, 1,
-                    computePivot(mTmpStartRect.left, 1 / scaleW),
-                    computePivot(mTmpStartRect.top, 1 / scaleH));
+                    computePivot(mTmpRect.left, 1 / scaleW),
+                    computePivot(mTmpRect.top, 1 / scaleH));
         }
 
         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
@@ -942,11 +998,13 @@
      * This animation is created when we are doing a thumbnail transition, for the activity that is
      * leaving, and the activity that is entering.
      */
-    Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
-            int appHeight, int transit, int taskId) {
+    Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, Rect containingFrame,
+            int transit, int taskId) {
+        final int appWidth = containingFrame.width();
+        final int appHeight = containingFrame.height();
         Bitmap thumbnailHeader = getAppTransitionThumbnailHeader(taskId);
         Animation a;
-        getDefaultNextAppTransitionStartRect(mTmpStartRect);
+        getDefaultNextAppTransitionStartRect(mTmpRect);
         final int thumbWidthI = thumbnailHeader != null ? thumbnailHeader.getWidth() : appWidth;
         final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
         final int thumbHeightI = thumbnailHeader != null ? thumbnailHeader.getHeight() : appHeight;
@@ -958,8 +1016,8 @@
                 float scaleW = thumbWidth / appWidth;
                 float scaleH = thumbHeight / appHeight;
                 a = new ScaleAnimation(scaleW, 1, scaleH, 1,
-                        computePivot(mTmpStartRect.left, scaleW),
-                        computePivot(mTmpStartRect.top, scaleH));
+                        computePivot(mTmpRect.left, scaleW),
+                        computePivot(mTmpRect.top, scaleH));
                 break;
             }
             case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
@@ -986,8 +1044,8 @@
                 float scaleW = thumbWidth / appWidth;
                 float scaleH = thumbHeight / appHeight;
                 Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
-                        computePivot(mTmpStartRect.left, scaleW),
-                        computePivot(mTmpStartRect.top, scaleH));
+                        computePivot(mTmpRect.left, scaleW),
+                        computePivot(mTmpRect.top, scaleH));
 
                 Animation alpha = new AlphaAnimation(1, 0);
 
@@ -1005,18 +1063,22 @@
         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
     }
 
-    private Animation createRelaunchAnimation(int appWidth, int appHeight,
-            Rect containingFrame) {
+    private Animation createRelaunchAnimation(Rect containingFrame, Rect contentInsets) {
         getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
         final int left = mTmpFromClipRect.left;
         final int top = mTmpFromClipRect.top;
         mTmpFromClipRect.offset(-left, -top);
-        mTmpToClipRect.set(0, 0, appWidth, appHeight);
+        // TODO: Isn't that strange that we ignore exact position of the containingFrame?
+        mTmpToClipRect.set(0, 0, containingFrame.width(), containingFrame.height());
         AnimationSet set = new AnimationSet(true);
         float fromWidth = mTmpFromClipRect.width();
         float toWidth = mTmpToClipRect.width();
         float fromHeight = mTmpFromClipRect.height();
-        float toHeight = mTmpToClipRect.height();
+        // While the window might span the whole display, the actual content will be cropped to the
+        // system decoration frame, for example when the window is docked. We need to take into
+        // account the visible height when constructing the animation.
+        float toHeight = mTmpToClipRect.height() - contentInsets.top - contentInsets.bottom;
+        int translateAdjustment = 0;
         if (fromWidth <= toWidth && fromHeight <= toHeight) {
             // The final window is larger in both dimensions than current window (e.g. we are
             // maximizing), so we can simply unclip the new window and there will be no disappearing
@@ -1026,12 +1088,17 @@
             // The disappearing window has one larger dimension. We need to apply scaling, so the
             // first frame of the entry animation matches the old window.
             set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
+            // We might not be going exactly full screen, but instead be aligned under the status
+            // bar using cropping. We still need to account for the cropped part, which will also
+            // be scaled.
+            translateAdjustment = (int) (contentInsets.top * fromHeight / toHeight);
         }
 
-        // We might not be going exactly full screen, but instead be aligned under the status bar.
-        // We need to take this into account when creating the translate animation.
+        // We animate the translation from the old position of the removed window, to the new
+        // position of the added window. The latter might not be full screen, for example docked for
+        // docked windows.
         TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
-                0, top - containingFrame.top, 0);
+                0, top - containingFrame.top - translateAdjustment, 0);
         set.addAnimation(translate);
         set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
         set.setZAdjustment(Animation.ZORDER_TOP);
@@ -1049,10 +1116,30 @@
                 && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL;
     }
 
+    /**
+     *
+     * @param frame These are the bounds of the window when it finishes the animation. This is where
+     *              the animation must usually finish in entrance animation, as the next frame will
+     *              display the window at these coordinates. In case of exit animation, this is
+     *              where the animation must start, as the frame before the animation is displaying
+     *              the window at these bounds.
+     * @param insets Knowing where the window will be positioned is not enough. Some parts of the
+     *               window might be obscured, usually by the system windows (status bar and
+     *               navigation bar) and we use content insets to convey that information. This
+     *               usually affects the animation aspects vertically, as the system decoration is
+     *               at the top and the bottom. For example when we animate from full screen to
+     *               recents, we want to exclude the covered parts, because they won't match the
+     *               thumbnail after the last frame is executed.
+     * @param surfaceInsets In rare situation the surface is larger than the content and we need to
+     *                      know about this to make the animation frames match. We currently use
+     *                      this for freeform windows, which have larger surfaces to display
+     *                      shadows. When we animate them from recents, we want to match the content
+     *                      to the recents thumbnail and hence need to account for the surface being
+     *                      bigger.
+     */
     Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
-            int appWidth, int appHeight, int orientation, Rect containingFrame, Rect contentInsets,
-            @Nullable Rect surfaceInsets, Rect appFrame, boolean isVoiceInteraction,
-            boolean resizedWindow, int taskId) {
+            int orientation, Rect frame, Rect insets, @Nullable Rect surfaceInsets,
+            boolean isVoiceInteraction, boolean freeform, int taskId) {
         Animation a;
         if (isVoiceInteraction && (transit == TRANSIT_ACTIVITY_OPEN
                 || transit == TRANSIT_TASK_OPEN
@@ -1075,7 +1162,7 @@
                     + " anim=" + a + " transit=" + appTransitionToString(transit)
                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
-            a = createRelaunchAnimation(appWidth, appHeight, containingFrame);
+            a = createRelaunchAnimation(frame, insets);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                     + " anim=" + a + " nextAppTransition=" + mNextAppTransition
@@ -1097,14 +1184,14 @@
                     + " transit=" + appTransitionToString(transit)
                     + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
-            a = createClipRevealAnimationLocked(transit, enter, appFrame);
+            a = createClipRevealAnimationLocked(transit, enter, frame);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                             + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
                             + " transit=" + appTransitionToString(transit)
                             + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
-            a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
+            a = createScaleUpAnimationLocked(transit, enter, frame);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                     + " anim=" + a + " nextAppTransition=ANIM_SCALE_UP"
@@ -1115,7 +1202,7 @@
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
             a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
-                    appWidth, appHeight, transit, taskId);
+                    frame, transit, taskId);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
@@ -1129,8 +1216,8 @@
             mNextAppTransitionScaleUp =
                     (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
             a = createAspectScaledThumbnailEnterExitAnimationLocked(
-                    getThumbnailTransitionState(enter), appWidth, appHeight, orientation, transit,
-                    containingFrame, contentInsets, surfaceInsets, resizedWindow, taskId);
+                    getThumbnailTransitionState(enter), orientation, transit, frame,
+                    insets, surfaceInsets, freeform, taskId);
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
                 String animName = mNextAppTransitionScaleUp ?
                         "ANIM_THUMBNAIL_ASPECT_SCALE_UP" : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN";
@@ -1286,7 +1373,8 @@
     }
 
     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback callback, boolean scaleUp) {
+            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
+            boolean scaleUp) {
         if (isTransitionSet()) {
             mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
                     : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
@@ -1308,7 +1396,8 @@
                 }
             }
             postAnimationCallback();
-            mNextAppTransitionCallback = callback;
+            mNextAppTransitionCallback = onAnimationStartedCallback;
+            mAnimationFinishedCallback = onAnimationFinishedCallback;
         } else {
             postAnimationCallback();
         }
@@ -1447,15 +1536,15 @@
                         pw.print(Integer.toHexString(mNextAppTransitionInPlace));
                 break;
             case NEXT_TRANSIT_TYPE_SCALE_UP: {
-                getDefaultNextAppTransitionStartRect(mTmpStartRect);
+                getDefaultNextAppTransitionStartRect(mTmpRect);
                 pw.print(prefix); pw.print("mNextAppTransitionStartX=");
-                        pw.print(mTmpStartRect.left);
+                        pw.print(mTmpRect.left);
                         pw.print(" mNextAppTransitionStartY=");
-                        pw.println(mTmpStartRect.top);
+                        pw.println(mTmpRect.top);
                 pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
-                        pw.print(mTmpStartRect.width());
+                        pw.print(mTmpRect.width());
                         pw.print(" mNextAppTransitionStartHeight=");
-                        pw.println(mTmpStartRect.height());
+                        pw.println(mTmpRect.height());
                 break;
             }
             case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 2828cd0..a61e83f 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -300,7 +300,8 @@
                 return false;
             }
 
-            if ((mAppToken.allDrawn || animating || mAppToken.startingDisplayed)
+            if ((mAppToken.allDrawn || mAppToken.mAnimatingWithSavedSurface
+                    || animating || mAppToken.startingDisplayed)
                     && animation != null) {
                 if (!animating) {
                     if (DEBUG_ANIM) Slog.v(TAG,
@@ -367,6 +368,7 @@
         return false;
     }
 
+    // This must be called while inside a transaction.
     boolean showAllWindowsLocked() {
         boolean isAnimating = false;
         final int NW = mAllAppWinAnimators.size();
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 5a1ed58..c5bd3a7 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -17,6 +17,9 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerService.TAG;
 
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.wm.WindowManagerService.H;
@@ -52,6 +55,13 @@
 
     final boolean voiceInteraction;
 
+    // Whether the window has a saved surface from last pause, which can be
+    // used to start an entering animation earlier.
+    boolean mHasSavedSurface;
+
+    // Whether we're performing an entering animation with a saved surface.
+    boolean mAnimatingWithSavedSurface;
+
     Task mTask;
     boolean appFullscreen;
     int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -114,11 +124,14 @@
     // This application will have its window replaced due to relaunch. This allows window manager
     // to differentiate between simple removal of a window and replacement. In the latter case it
     // will preserve the old window until the new one is drawn.
-    boolean mReplacingWindow;
+    boolean mWillReplaceWindow;
     // If true, the replaced window was already requested to be removed.
     boolean mReplacingRemoveRequested;
     // Whether the replacement of the window should trigger app transition animation.
     boolean mAnimateReplacingWindow;
+    // If not null, the window that will be used to replace the old one. This is being set when
+    // the window is added and unset when this window reports its first draw.
+    WindowState mReplacingWindow;
 
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
@@ -257,10 +270,13 @@
         final int N = allAppWindows.size();
         for (int i=0; i<N; i++) {
             WindowState win = allAppWindows.get(i);
+            // If we're animating with a saved surface, we're already visible.
+            // Return true so that the alpha doesn't get cleared.
             if (!win.mAppFreezing
-                    && (win.mViewVisibility == View.VISIBLE ||
-                        (win.mWinAnimator.isAnimating() &&
-                                !service.mAppTransition.isTransitionSet()))
+                    && (win.mViewVisibility == View.VISIBLE
+                    || mAnimatingWithSavedSurface
+                    || (win.mWinAnimator.isAnimating() &&
+                            !service.mAppTransition.isTransitionSet()))
                     && !win.mDestroying && win.isDrawnLw()) {
                 return true;
             }
@@ -283,6 +299,52 @@
         }
     }
 
+    /**
+     * Checks whether we should save surfaces for this app.
+     *
+     * @return true if the surfaces should be saved, false otherwise.
+     */
+    boolean shouldSaveSurface() {
+        // We want to save surface if the app's windows are "allDrawn", or if we're
+        // currently animating with save surfaces. (If the app didn't even finish
+        // drawing when the user exits, but we have a saved surface from last time,
+        // we still want to keep that surface.)
+        mHasSavedSurface = allDrawn || mAnimatingWithSavedSurface;
+        if (mHasSavedSurface) {
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "Saving surface: " + this);
+            return true;
+        }
+        return false;
+    }
+
+    void restoreSavedSurfaces() {
+        if (!mHasSavedSurface) {
+            return;
+        }
+
+        if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                "Restoring saved surfaces: " + this + ", allDrawn=" + allDrawn);
+
+        mHasSavedSurface = false;
+        mAnimatingWithSavedSurface = true;
+        for (int i = windows.size() - 1; i >= 0; i--) {
+            WindowState ws = windows.get(i);
+            ws.mWinAnimator.mDrawState = WindowStateAnimator.READY_TO_SHOW;
+        }
+    }
+
+    void destroySavedSurfaces() {
+        if (mHasSavedSurface) {
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "Destroying saved surface: " + this);
+            for (int i = windows.size() - 1; i >= 0; i--) {
+                final WindowState win = windows.get(i);
+                win.mWinAnimator.destroySurfaceLocked();
+            }
+        }
+    }
+
     @Override
     void removeAllWindows() {
         for (int winNdx = allAppWindows.size() - 1; winNdx >= 0;
diff --git a/services/core/java/com/android/server/wm/CircularDisplayMask.java b/services/core/java/com/android/server/wm/CircularDisplayMask.java
index 7c2da2d..be3e922 100644
--- a/services/core/java/com/android/server/wm/CircularDisplayMask.java
+++ b/services/core/java/com/android/server/wm/CircularDisplayMask.java
@@ -56,7 +56,7 @@
             int screenOffset, int maskThickness) {
         mScreenSize = new Point();
         display.getSize(mScreenSize);
-        if (mScreenSize.x != mScreenSize.y) {
+        if (mScreenSize.x != mScreenSize.y + screenOffset) {
             Slog.w(TAG, "Screen dimensions of displayId = " + display.getDisplayId() +
                     "are not equal, circularMask will not be drawn.");
             mDimensionsUnequal = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 39479c1..fab8ee5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -18,7 +18,7 @@
 
 import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
-
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
@@ -243,10 +243,30 @@
     }
 
     void moveStack(TaskStack stack, boolean toTop) {
+        if (stack.mStackId == PINNED_STACK_ID && !toTop) {
+            // Pinned stack is always-on-top silly...
+            Slog.w(TAG, "Ignoring move of always-on-top stack=" + stack + " to bottom");
+            return;
+        }
+
         if (!mStacks.remove(stack)) {
             Slog.wtf(TAG, "moving stack that was not added: " + stack, new Throwable());
         }
-        mStacks.add(toTop ? mStacks.size() : 0, stack);
+
+        int addIndex = toTop ? mStacks.size() : 0;
+
+        if (toTop
+                && mService.isStackVisibleLocked(PINNED_STACK_ID)
+                && stack.mStackId != PINNED_STACK_ID) {
+            // The pinned stack is always the top most stack (always-on-top) when it is visible.
+            // So, stack is moved just below the pinned stack.
+            addIndex--;
+            TaskStack topStack = mStacks.get(addIndex);
+            if (topStack.mStackId != PINNED_STACK_ID) {
+                throw new IllegalStateException("Pinned stack isn't top stack??? " + mStacks);
+            }
+        }
+        mStacks.add(addIndex, stack);
     }
 
     void detachStack(TaskStack stack) {
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 2d87123..04cba81 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,6 +18,8 @@
 
 import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.view.PointerIcon.STYLE_HORIZONTAL_DOUBLE_ARROW;
+import static android.view.PointerIcon.STYLE_VERTICAL_DOUBLE_ARROW;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -87,6 +89,8 @@
         final boolean landscape = configuration.orientation == ORIENTATION_LANDSCAPE;
         final int width = landscape ? mDividerWidth : MATCH_PARENT;
         final int height = landscape ? MATCH_PARENT : mDividerWidth;
+        view.setPointerShape(
+                landscape ? STYLE_HORIZONTAL_DOUBLE_ARROW : STYLE_VERTICAL_DOUBLE_ARROW);
         WindowManager.LayoutParams params = new WindowManager.LayoutParams(
                 width, height, TYPE_DOCK_DIVIDER,
                 FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 3521682..f35ea66 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -77,7 +77,6 @@
         mSurfaceControl = surface;
         mFlags = flags;
         mLocalWin = localWin;
-        mUid = Binder.getCallingUid();
         mNotifiedWindows = new ArrayList<WindowState>();
     }
 
@@ -265,21 +264,27 @@
     }
 
     void broadcastDragEndedLw() {
+        final int myPid = Process.myPid();
+
         if (WindowManagerService.DEBUG_DRAG) {
             Slog.d(WindowManagerService.TAG, "broadcasting DRAG_ENDED");
         }
-        DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
-                0, 0, null, null, null, null, mDragResult);
-        for (WindowState ws: mNotifiedWindows) {
+        for (WindowState ws : mNotifiedWindows) {
+            DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
+                    0, 0, null, null, null, null, mDragResult);
             try {
                 ws.mClient.dispatchDragEvent(evt);
             } catch (RemoteException e) {
                 Slog.w(WindowManagerService.TAG, "Unable to drag-end window " + ws);
             }
+            // if the current window is in the same process,
+            // the dispatch has already recycled the event
+            if (myPid != ws.mSession.mPid) {
+                evt.recycle();
+            }
         }
         mNotifiedWindows.clear();
         mDragInProgress = false;
-        evt.recycle();
     }
 
     void endDragLw() {
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 6c391ad..f999402 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -17,7 +17,9 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
+import static com.android.server.wm.WindowManagerService.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerService.DEBUG_INPUT;
+
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -60,8 +62,6 @@
     private final Object mInputDevicesReadyMonitor = new Object();
     private boolean mInputDevicesReady;
 
-    Rect mTmpRect = new Rect();
-
     public InputMonitor(WindowManagerService service) {
         mService = service;
     }
@@ -174,17 +174,7 @@
             final boolean hasFocus, final boolean hasWallpaper, DisplayContent displayContent) {
         // Add a window to our list of input windows.
         inputWindowHandle.name = child.toString();
-        final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
-        if (modal && child.mAppToken != null) {
-            // Limit the outer touch to the activity stack region.
-            flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            child.getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
-            inputWindowHandle.touchableRegion.set(mTmpRect);
-        } else {
-            // Not modal or full screen modal
-            child.getTouchableRegion(inputWindowHandle.touchableRegion);
-        }
+        flags = child.getTouchableRegion(inputWindowHandle.touchableRegion, flags, this);
         inputWindowHandle.layoutParamsFlags = flags;
         inputWindowHandle.layoutParamsType = type;
         inputWindowHandle.dispatchingTimeoutNanos = child.getInputDispatchingTimeoutNanos();
@@ -227,7 +217,9 @@
             inputWindowHandle.scaleFactor = 1;
         }
 
-
+        if (DEBUG_INPUT) {
+            Slog.d(WindowManagerService.TAG, "addInputWindowHandle: " + inputWindowHandle);
+        }
         addInputWindowHandleLw(inputWindowHandle);
     }
 
@@ -428,7 +420,7 @@
      * Layer assignment is assumed to be complete by the time this is called.
      */
     public void setInputFocusLw(WindowState newWindow, boolean updateInputWindows) {
-        if (WindowManagerService.DEBUG_FOCUS_LIGHT || WindowManagerService.DEBUG_INPUT) {
+        if (DEBUG_FOCUS_LIGHT || DEBUG_INPUT) {
             Slog.d(WindowManagerService.TAG, "Input focus has changed to " + newWindow);
         }
 
@@ -464,7 +456,7 @@
 
     public void pauseDispatchingLw(WindowToken window) {
         if (! window.paused) {
-            if (WindowManagerService.DEBUG_INPUT) {
+            if (DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Pausing WindowToken " + window);
             }
 
@@ -475,7 +467,7 @@
 
     public void resumeDispatchingLw(WindowToken window) {
         if (window.paused) {
-            if (WindowManagerService.DEBUG_INPUT) {
+            if (DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Resuming WindowToken " + window);
             }
 
@@ -486,7 +478,7 @@
 
     public void freezeInputDispatchingLw() {
         if (! mInputDispatchFrozen) {
-            if (WindowManagerService.DEBUG_INPUT) {
+            if (DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Freezing input dispatching");
             }
 
@@ -497,7 +489,7 @@
 
     public void thawInputDispatchingLw() {
         if (mInputDispatchFrozen) {
-            if (WindowManagerService.DEBUG_INPUT) {
+            if (DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Thawing input dispatching");
             }
 
@@ -508,7 +500,7 @@
 
     public void setEventDispatchingLw(boolean enabled) {
         if (mInputDispatchEnabled != enabled) {
-            if (WindowManagerService.DEBUG_INPUT) {
+            if (DEBUG_INPUT) {
                 Slog.v(WindowManagerService.TAG, "Setting event dispatching to " + enabled);
             }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7c56180..ad44196 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -17,12 +17,15 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.HOME_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
-import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
+
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
@@ -187,7 +190,8 @@
                 bounds = mTmpRect;
                 mFullscreen = true;
             } else {
-                if (mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID || bounds.isEmpty()) {
+                if ((mStack.mStackId != FREEFORM_WORKSPACE_STACK_ID
+                        && mStack.mStackId != PINNED_STACK_ID) || bounds.isEmpty()) {
                     // ensure bounds are entirely within the display rect
                     if (!bounds.intersect(mTmpRect)) {
                         // Can't set bounds outside the containing display...Sorry!
@@ -241,8 +245,7 @@
     private boolean useCurrentBounds() {
         final DisplayContent displayContent = mStack.getDisplayContent();
         if (mFullscreen
-                || mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID
-                || mStack.mStackId == DOCKED_STACK_ID
+                || mStack.allowTaskResize()
                 || displayContent == null
                 || displayContent.getDockedStackLocked() != null) {
             return true;
@@ -322,6 +325,10 @@
         return (tokensCount != 0) && mAppTokens.get(tokensCount - 1).showForAllUsers;
     }
 
+    boolean inHomeStack() {
+        return mStack != null && mStack.mStackId == HOME_STACK_ID;
+    }
+
     boolean inFreeformWorkspace() {
         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
     }
@@ -335,6 +342,11 @@
         return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
     }
 
+    AppWindowToken getTopAppWindowToken() {
+        final int tokensCount = mAppTokens.size();
+        return tokensCount > 0 ? mAppTokens.get(tokensCount - 1) : null;
+    }
+
     @Override
     public boolean isFullscreen() {
         if (useCurrentBounds()) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 6734fd6..df664bd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.LAST_STATIC_STACK_ID;
+import static android.app.ActivityManager.PINNED_STACK_ID;
 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
 import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
 import static com.android.server.wm.WindowManagerService.TAG;
@@ -123,7 +124,8 @@
 
     boolean allowTaskResize() {
         return mStackId == FREEFORM_WORKSPACE_STACK_ID
-                || mStackId == DOCKED_STACK_ID;
+                || mStackId == DOCKED_STACK_ID
+                || mStackId == PINNED_STACK_ID;
     }
 
     /**
@@ -202,6 +204,7 @@
     private boolean useCurrentBounds() {
         if (mFullscreen
                 || mStackId == DOCKED_STACK_ID
+                || mStackId == PINNED_STACK_ID
                 || mDisplayContent == null
                 || mDisplayContent.getDockedStackLocked() != null) {
             return true;
@@ -393,7 +396,7 @@
 
         Rect bounds = null;
         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
-        if (mStackId == DOCKED_STACK_ID || (dockedStack != null
+        if (mStackId == DOCKED_STACK_ID || (dockedStack != null && mStackId != PINNED_STACK_ID
                 && mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID)) {
             // The existence of a docked stack affects the size of any static stack created since
             // the docked stack occupies a dedicated region on screen.
@@ -406,7 +409,7 @@
             final boolean dockedOnTopOrLeft = WindowManagerService.sDockedStackCreateMode
                     == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
             getStackDockedModeBounds(mTmpRect, bounds, mStackId, mTmpRect2,
-                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment(),
+                    mDisplayContent.mDividerControllerLocked.getWidth(),
                     dockedOnTopOrLeft);
         }
 
@@ -422,6 +425,7 @@
 
     void getStackDockedModeBoundsLocked(Rect outBounds) {
         if (mStackId == DOCKED_STACK_ID
+                || mStackId == PINNED_STACK_ID
                 || mStackId > LAST_STATIC_STACK_ID
                 || mDisplayContent == null) {
             outBounds.set(mBounds);
@@ -455,7 +459,7 @@
         dockedStack.getRawBounds(mTmpRect2);
         final boolean dockedOnTopOrLeft = dockedSide == DOCKED_TOP || dockedSide == DOCKED_LEFT;
         getStackDockedModeBounds(mTmpRect, outBounds, mStackId, mTmpRect2,
-                mDisplayContent.mDividerControllerLocked.getWidthAdjustment(), dockedOnTopOrLeft);
+                mDisplayContent.mDividerControllerLocked.getWidth(), dockedOnTopOrLeft);
 
     }
 
@@ -465,13 +469,13 @@
      * @param outBounds Output bounds that should be used for the stack.
      * @param stackId Id of stack we are calculating the bounds for.
      * @param dockedBounds Bounds of the docked stack.
-     * @param adjustment Additional adjustment to make to the output bounds close to the side of the
-     *                   dock.
-     * @param dockOntopOrLeft If the docked stack is on the top or left side of the screen.
+     * @param dockDividerWidth We need to know the width of the divider make to the output bounds
+     *                         close to the side of the dock.
+     * @param dockOnTopOrLeft If the docked stack is on the top or left side of the screen.
      */
     private static void getStackDockedModeBounds(
-            Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int adjustment,
-            boolean dockOntopOrLeft) {
+            Rect displayRect, Rect outBounds, int stackId, Rect dockedBounds, int dockDividerWidth,
+            boolean dockOnTopOrLeft) {
         final boolean dockedStack = stackId == DOCKED_STACK_ID;
         final boolean splitHorizontally = displayRect.width() > displayRect.height();
 
@@ -480,34 +484,34 @@
             // The initial bounds of the docked stack when it is created half the screen space and
             // its bounds can be adjusted after that. The bounds of all other stacks are adjusted
             // to occupy whatever screen space the docked stack isn't occupying.
-            if (dockOntopOrLeft) {
+            if (dockOnTopOrLeft) {
                 if (splitHorizontally) {
-                    outBounds.right = displayRect.centerX() - adjustment;
+                    outBounds.right = displayRect.centerX() - dockDividerWidth / 2;
                 } else {
-                    outBounds.bottom = displayRect.centerY() - adjustment;
+                    outBounds.bottom = displayRect.centerY() - dockDividerWidth / 2;
                 }
             } else {
                 if (splitHorizontally) {
-                    outBounds.left = displayRect.centerX() + adjustment;
+                    outBounds.left = displayRect.centerX() + dockDividerWidth / 2;
                 } else {
-                    outBounds.top = displayRect.centerY() + adjustment;
+                    outBounds.top = displayRect.centerY() + dockDividerWidth / 2;
                 }
             }
             return;
         }
 
         // Other stacks occupy whatever space is left by the docked stack.
-        if (!dockOntopOrLeft) {
+        if (!dockOnTopOrLeft) {
             if (splitHorizontally) {
-                outBounds.right = dockedBounds.left - adjustment;
+                outBounds.right = dockedBounds.left - dockDividerWidth;
             } else {
-                outBounds.bottom = dockedBounds.top - adjustment;
+                outBounds.bottom = dockedBounds.top - dockDividerWidth;
             }
         } else {
             if (splitHorizontally) {
-                outBounds.left = dockedBounds.right + adjustment;
+                outBounds.left = dockedBounds.right + dockDividerWidth;
             } else {
-                outBounds.top = dockedBounds.bottom + adjustment;
+                outBounds.top = dockedBounds.bottom + dockDividerWidth;
             }
         }
     }
@@ -533,7 +537,7 @@
         for (int i = 0; i < count; i++) {
             final TaskStack otherStack = mService.mStackIdToStack.valueAt(i);
             final int otherStackId = otherStack.mStackId;
-            if (otherStackId != DOCKED_STACK_ID
+            if (otherStackId != DOCKED_STACK_ID && mStackId != PINNED_STACK_ID
                     && otherStackId >= FIRST_STATIC_STACK_ID
                     && otherStackId <= LAST_STATIC_STACK_ID) {
                 mService.mH.sendMessage(
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 928a117..f4a4140 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -31,6 +31,7 @@
 
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.TimeUtils;
@@ -413,7 +414,7 @@
 
             final AppWindowToken atoken = win.mAppToken;
             if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
-                if (atoken == null || atoken.allDrawn) {
+                if (atoken == null || atoken.allDrawn || atoken.mAnimatingWithSavedSurface) {
                     if (winAnimator.performShowLocked()) {
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
@@ -731,8 +732,15 @@
             mWindowPlacerLocked.requestTraversal();
         }
 
+        if (mAnimating && !wasAnimating && Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+            Trace.asyncTraceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+        }
+
         if (!mAnimating && wasAnimating) {
             mWindowPlacerLocked.requestTraversal();
+            if (Trace.isTagEnabled(Trace.TRACE_TAG_WINDOW_MANAGER)) {
+                Trace.asyncTraceEnd(Trace.TRACE_TAG_WINDOW_MANAGER, "animating", 0);
+            }
         }
 
         mService.destroyPreservedSurfaceLocked();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cd5fbb0..75680a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1327,8 +1327,14 @@
             addAttachedWindowToListLocked(win, addToToken);
         }
 
-        if (win.mAppToken != null && addToToken) {
-            win.mAppToken.allAppWindows.add(win);
+        final AppWindowToken appToken = win.mAppToken;
+        if (appToken != null) {
+            if (addToToken) {
+                appToken.allAppWindows.add(win);
+            }
+            if (appToken.mWillReplaceWindow) {
+                appToken.mReplacingWindow = win;
+            }
         }
     }
 
@@ -2053,7 +2059,7 @@
     }
 
     private void prepareWindowReplacementTransition(AppWindowToken atoken) {
-        if (atoken == null || !atoken.mReplacingWindow || !atoken.mAnimateReplacingWindow) {
+        if (atoken == null || !atoken.mWillReplaceWindow || !atoken.mAnimateReplacingWindow) {
             return;
         }
         atoken.allDrawn = false;
@@ -2157,6 +2163,8 @@
                 + " isAnimating=" + win.mWinAnimator.isAnimating()
                 + " app-animation="
                 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
+                + " mWillReplaceWindow="
+                + (win.mAppToken != null ? win.mAppToken.mWillReplaceWindow : false)
                 + " inPendingTransaction="
                 + (win.mAppToken != null ? win.mAppToken.inPendingTransaction : false)
                 + " mDisplayFrozen=" + mDisplayFrozen);
@@ -2168,8 +2176,8 @@
         // animation wouldn't be seen.
         if (win.mHasSurface && okToDisplay()) {
             final AppWindowToken appToken = win.mAppToken;
-            if (appToken != null && appToken.mReplacingWindow) {
-                // This window is going to be replaced. We need to kepp it around until the new one
+            if (appToken != null && appToken.mWillReplaceWindow) {
+                // This window is going to be replaced. We need to keep it around until the new one
                 // gets added, then we will get rid of this one.
                 if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Preserving " + win + " until the new one is "
                         + "added");
@@ -2629,6 +2637,11 @@
                     }
                 }
                 dragResizing = win.isDragResizing();
+                if (win.isAnimatingWithSavedSurface()) {
+                    // If we're animating with a saved surface now, request client to report draw.
+                    // We still need to know when the real thing is drawn.
+                    toBeDisplayed = true;
+                }
                 try {
                     if (!win.mHasSurface) {
                         surfaceChanged = true;
@@ -2679,9 +2692,14 @@
                 if (winAnimator.mSurfaceControl != null) {
                     if (DEBUG_VISIBILITY) Slog.i(TAG, "Relayout invis " + win
                             + ": mExiting=" + win.mExiting);
+                    // If we are using a saved surface to do enter animation, just let the
+                    // animation run and don't destroy the surface. This could happen when
+                    // the app sets visibility to invisible for the first time after resume,
+                    // or when the user exits immediately after a resume. In both cases, we
+                    // don't want to destroy the saved surface.
                     // If we are not currently running the exit animation, we
                     // need to see about starting one.
-                    if (!win.mExiting) {
+                    if (!win.mExiting && !win.isAnimatingWithSavedSurface()) {
                         surfaceChanged = true;
                         // Try starting an animation; if there isn't one, we
                         // can destroy the surface right away.
@@ -2707,7 +2725,9 @@
                             if (mInputMethodWindow == win) {
                                 mInputMethodWindow = null;
                             }
-                            winAnimator.destroySurfaceLocked();
+                            if (!win.shouldSaveSurface()) {
+                                winAnimator.destroySurfaceLocked();
+                            }
                         }
                         //TODO (multidisplay): Magnification is supported only for the default
                         if (mAccessibilityController != null
@@ -2833,7 +2853,8 @@
         try {
             synchronized (mWindowMap) {
                 WindowState win = windowForClientLocked(session, client, false);
-                if (DEBUG_ADD_REMOVE) Slog.d(TAG, "finishDrawingWindow: " + win);
+                if (DEBUG_ADD_REMOVE) Slog.d(TAG, "finishDrawingWindow: " + win + " mDrawState="
+                        + (win != null ? win.mWinAnimator.drawStateToString() : "null"));
                 if (win != null && win.mWinAnimator.finishDrawingLocked()) {
                     if ((win.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                         getDefaultDisplayContentLocked().pendingLayoutChanges |=
@@ -2862,46 +2883,44 @@
                     "applyAnimation: atoken=" + atoken);
 
             // Determine the visible rect to calculate the thumbnail clip
-            WindowState win = atoken.findMainWindow();
-            Rect containingFrame = new Rect(0, 0, width, height);
-            Rect contentInsets = new Rect();
-            Rect appFrame = new Rect(0, 0, width, height);
+            final WindowState win = atoken.findMainWindow();
+            final Rect frame = new Rect(0, 0, width, height);
+            final Rect insets = new Rect();
             Rect surfaceInsets = null;
             final boolean fullscreen = win != null && win.isFullscreen(width, height);
             final boolean freeform = win != null && win.inFreeformWorkspace();
+            final boolean docked = win != null && win.inDockedWorkspace();
             if (win != null) {
                 // Containing frame will usually cover the whole screen, including dialog windows.
                 // For freeform workspace windows it will not cover the whole screen and it also
                 // won't exactly match the final freeform window frame (e.g. when overlapping with
                 // the status bar). In that case we need to use the final frame.
                 if (freeform) {
-                    containingFrame.set(win.mFrame);
+                    frame.set(win.mFrame);
                 } else {
-                    containingFrame.set(win.mContainingFrame);
+                    frame.set(win.mContainingFrame);
                 }
                 surfaceInsets = win.getAttrs().surfaceInsets;
-                if (fullscreen) {
+                if (fullscreen || docked) {
                     // For fullscreen windows use the window frames and insets to set the thumbnail
-                    // clip. For none-fullscreen windows we use the app display region so the clip
+                    // clip. For non-fullscreen windows we use the app display region so the clip
                     // isn't affected by the window insets.
-                    contentInsets.set(win.mContentInsets);
-                    appFrame.set(win.mFrame);
-                } else {
-                    appFrame.set(containingFrame);
+                    insets.set(win.mContentInsets);
                 }
             }
 
-            final int containingWidth = containingFrame.width();
-            final int containingHeight = containingFrame.height();
             if (atoken.mLaunchTaskBehind) {
                 // Differentiate the two animations. This one which is briefly on the screen
                 // gets the !enter animation, and the other activity which remains on the
                 // screen gets the enter animation. Both appear in the mOpeningApps set.
                 enter = false;
             }
-            Animation a = mAppTransition.loadAnimation(lp, transit, enter, containingWidth,
-                    containingHeight, mCurConfiguration.orientation, containingFrame, contentInsets,
-                    surfaceInsets, appFrame, isVoiceInteraction, freeform, atoken.mTask.mTaskId);
+            if (DEBUG_APP_TRANSITIONS) Slog.d(TAG, "Loading animation for app transition."
+                    + " transit=" + AppTransition.appTransitionToString(transit) + " enter=" + enter
+                    + " frame=" + frame + " insets=" + insets + " surfaceInsets=" + surfaceInsets);
+            Animation a = mAppTransition.loadAnimation(lp, transit, enter,
+                    mCurConfiguration.orientation, frame, insets, surfaceInsets, isVoiceInteraction,
+                    freeform, atoken.mTask.mTaskId);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -2911,6 +2930,8 @@
                     }
                     Slog.v(TAG, "Loaded animation " + a + " for " + atoken, e);
                 }
+                final int containingWidth = frame.width();
+                final int containingHeight = frame.height();
                 atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
                         mAppTransition.canSkipFirstFrame());
             }
@@ -3262,10 +3283,8 @@
             }
         }
 
-        final TaskStack dockedStack = mStackIdToStack.get(DOCKED_STACK_ID);
-        final TaskStack freeformStack = mStackIdToStack.get(FREEFORM_WORKSPACE_STACK_ID);
-        if ((dockedStack != null && dockedStack.isVisibleLocked())
-                || (freeformStack != null && freeformStack.isVisibleLocked())) {
+        if (isStackVisibleLocked(DOCKED_STACK_ID)
+                || isStackVisibleLocked(FREEFORM_WORKSPACE_STACK_ID)) {
             // We don't let app affect the system orientation when in freeform or docked mode since
             // they don't occupy the entire display and their request can conflict with other apps.
             return SCREEN_ORIENTATION_UNSPECIFIED;
@@ -3618,9 +3637,11 @@
 
     @Override
     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback callback, boolean scaleUp) {
+            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
+            boolean scaleUp) {
         synchronized (mWindowMap) {
-            mAppTransition.overridePendingAppTransitionMultiThumb(specs, callback, scaleUp);
+            mAppTransition.overridePendingAppTransitionMultiThumb(specs, onAnimationStartedCallback,
+                    onAnimationFinishedCallback, scaleUp);
         }
     }
 
@@ -3909,7 +3930,7 @@
         // transition animation
         // * or this is an opening app and windows are being replaced.
         if (wtoken.hidden == visible || (wtoken.hidden && wtoken.mIsExiting) ||
-                (visible && wtoken.mReplacingWindow)) {
+                (visible && wtoken.mWillReplaceWindow)) {
             boolean changed = false;
             if (DEBUG_APP_TRANSITIONS) Slog.v(
                 TAG, "Changing app " + wtoken + " hidden=" + wtoken.hidden
@@ -4496,6 +4517,11 @@
         }
     }
 
+    boolean isStackVisibleLocked(int stackId) {
+        final TaskStack stack = mStackIdToStack.get(stackId);
+        return (stack != null && stack.isVisibleLocked());
+    }
+
     public void setDockedStackCreateMode(int mode) {
         synchronized (mWindowMap) {
             sDockedStackCreateMode = mode;
@@ -4657,7 +4683,7 @@
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, configs, taskBounds)) {
+            if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
                 mWindowPlacerLocked.performSurfacePlacement();
@@ -4710,6 +4736,26 @@
         }
     }
 
+    /**
+     * Starts deferring layout passes. Useful when doing multiple changes but to optimize
+     * performance, only one layout pass should be done. This can be called multiple times, and
+     * layouting will be resumed once the last caller has called {@link #continueSurfaceLayout}
+     */
+    public void deferSurfaceLayout() {
+        synchronized (mWindowMap) {
+            mWindowPlacerLocked.deferLayout();
+        }
+    }
+
+    /**
+     * Resumes layout passes after deferring them. See {@link #deferSurfaceLayout()}
+     */
+    public void continueSurfaceLayout() {
+        synchronized (mWindowMap) {
+            mWindowPlacerLocked.continueLayout();
+        }
+    }
+
     public void getTaskBounds(int taskId, Rect bounds) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -5396,8 +5442,8 @@
                 if (visible) {
                     // TODO(multi-display): support multiple displays
                     if (mCircularDisplayMask == null) {
-                        int screenOffset = mContext.getResources().getDimensionPixelSize(
-                                com.android.internal.R.dimen.circular_display_mask_offset);
+                        int screenOffset = mContext.getResources().getInteger(
+                                com.android.internal.R.integer.config_windowOutsetBottom);
                         int maskThickness = mContext.getResources().getDimensionPixelSize(
                                 com.android.internal.R.dimen.circular_display_mask_thickness);
 
@@ -6070,6 +6116,10 @@
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
             WindowState w = windows.get(i);
+            // Discard surface after orientation change, these can't be reused.
+            if (w.mAppToken != null) {
+                w.mAppToken.destroySavedSurfaces();
+            }
             if (w.mHasSurface) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
@@ -6972,7 +7022,7 @@
                     + " asbinder=" + window.asBinder());
         }
 
-        final int callerPid = Binder.getCallingPid();
+        final int callerUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         IBinder token = null;
 
@@ -6997,6 +7047,7 @@
                         final IBinder winBinder = window.asBinder();
                         token = new Binder();
                         mDragState = new DragState(this, token, surface, flags, winBinder);
+                        mDragState.mUid = callerUid;
                         token = mDragState.mToken = new Binder();
 
                         // 5 second timeout for this window to actually begin the drag
@@ -8346,7 +8397,7 @@
                 final int numTokens = tokens.size();
                 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (wtoken.mIsExiting && !wtoken.mReplacingWindow) {
+                    if (wtoken.mIsExiting && !wtoken.mWillReplaceWindow) {
                         continue;
                     }
                     i = reAddAppWindowsLocked(displayContent, i, wtoken);
@@ -8416,7 +8467,8 @@
             } else if (wtoken != null) {
                 winAnimator.mAnimLayer =
                         w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
-                if (wtoken.mReplacingWindow && wtoken.mAnimateReplacingWindow) {
+                if (wtoken.mWillReplaceWindow && wtoken.mAnimateReplacingWindow &&
+                        wtoken.mReplacingWindow != w) {
                     // We know that we will be animating a relaunching window in the near future,
                     // which will receive a z-order increase. We want the replaced window to
                     // immediately receive the same treatment, e.g. to be above the dock divider.
@@ -8723,12 +8775,14 @@
                         } else if (ws.mAppToken != null && ws.mAppToken.clientHidden) {
                             Slog.w(TAG, "LEAKED SURFACE (app token hidden): "
                                     + ws + " surface=" + wsa.mSurfaceControl
-                                    + " token=" + ws.mAppToken);
+                                    + " token=" + ws.mAppToken
+                                    + " saved=" + ws.mAppToken.mHasSavedSurface);
                             if (SHOW_TRANSACTIONS) logSurface(ws, "LEAK DESTROY", null);
                             wsa.mSurfaceControl.destroy();
                             wsa.mSurfaceShown = false;
                             wsa.mSurfaceControl = null;
                             ws.mHasSurface = false;
+                            ws.mAppToken.mHasSavedSurface = false;
                             leakedSurface = true;
                         }
                     }
@@ -9962,7 +10016,9 @@
                 Slog.w(TAG, "Attempted to set replacing window on non-existing app token " + token);
                 return;
             }
-            appWindowToken.mReplacingWindow = true;
+            if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Marking app token " + appWindowToken
+                    + " as replacing window.");
+            appWindowToken.mWillReplaceWindow = true;
             appWindowToken.mAnimateReplacingWindow = animate;
         }
     }
@@ -10168,8 +10224,7 @@
         @Override
         public boolean isStackVisible(int stackId) {
             synchronized (mWindowMap) {
-                final TaskStack stack = mStackIdToStack.get(stackId);
-                return (stack != null && stack.isVisibleLocked());
+                return WindowManagerService.this.isStackVisibleLocked(stackId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7ea64f1..5bc329e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -28,6 +28,9 @@
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
@@ -35,6 +38,7 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.graphics.Point;
 import android.os.PowerManager;
@@ -55,7 +59,6 @@
 import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -446,7 +449,8 @@
                     + WindowManagerService.TYPE_LAYER_OFFSET;
             mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
             mAttachedWindow = attachedWindow;
-            if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to " + mAttachedWindow);
+            if (WindowManagerService.DEBUG_ADD_REMOVE) Slog.v(TAG, "Adding " + this + " to "
+                    + mAttachedWindow);
 
             final WindowList childWindows = mAttachedWindow.mChildWindows;
             final int numChildWindows = childWindows.size();
@@ -552,7 +556,7 @@
     @Override
     public void computeFrameLw(Rect pf, Rect df, Rect of, Rect cf, Rect vf, Rect dcf, Rect sf,
             Rect osf) {
-        if (mAppToken != null && mAppToken.mReplacingWindow
+        if (mAppToken != null && mAppToken.mWillReplaceWindow
                 && (mExiting || !mAppToken.mReplacingRemoveRequested)) {
             // This window is being replaced and either already got information that it's being
             // removed or we are still waiting for some information. Because of this we don't
@@ -1307,10 +1311,12 @@
 
     void maybeRemoveReplacedWindow() {
         AppWindowToken token = mAppToken;
-        if (token != null && token.mReplacingWindow) {
-            token.mReplacingWindow = false;
+        if (token != null && token.mWillReplaceWindow && token.mReplacingWindow == this) {
+            if (DEBUG_ADD_REMOVE) Slog.d(TAG, "Removing replacing window: " + this);
+            token.mWillReplaceWindow = false;
             token.mAnimateReplacingWindow = false;
             token.mReplacingRemoveRequested = false;
+            token.mReplacingWindow = null;
             for (int i = token.allAppWindows.size() - 1; i >= 0; i--) {
                 WindowState win = token.allAppWindows.get(i);
                 if (win.mExiting) {
@@ -1330,6 +1336,37 @@
         return mAppToken != null && mAppToken.mTask != null && mAppToken.mTask.inDockedWorkspace();
     }
 
+    int getTouchableRegion(Region region, int flags, InputMonitor inputMonitor) {
+        final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)) == 0;
+        if (modal && mAppToken != null) {
+            // Limit the outer touch to the activity stack region.
+            flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+            if (!inFreeformWorkspace()) {
+                // If this is a modal window we need to dismiss it if it's not full screen and the
+                // touch happens outside of the frame that displays the content. This means we
+                // need to intercept touches outside of that window. The dim layer user
+                // associated with the window (task or stack) will give us the good bounds, as
+                // they would be used to display the dim layer.
+                final DimLayer.DimLayerUser dimLayerUser = getDimLayerUser();
+                if (dimLayerUser != null) {
+                    dimLayerUser.getBounds(mTmpRect);
+                } else {
+                    getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
+                }
+            } else {
+                // For freeform windows we the touch region to include the whole surface for the
+                // shadows.
+                getVisibleBounds(mTmpRect, BOUNDS_FOR_TOUCH);
+            }
+            region.set(mTmpRect);
+        } else {
+            // Not modal or full screen modal
+            getTouchableRegion(region);
+        }
+        return flags;
+    }
+
     private class DeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
@@ -1501,6 +1538,28 @@
         return mExiting || (mService.mClosingApps.contains(mAppToken));
     }
 
+    boolean isAnimatingWithSavedSurface() {
+        return mAppToken != null && mAppToken.mAnimatingWithSavedSurface;
+    }
+
+    boolean shouldSaveSurface() {
+        if (ActivityManager.isLowRamDeviceStatic()) {
+            // Don't save surfaces on Svelte devices.
+            return false;
+        }
+
+        Task task = getTask();
+        if (task == null || task.inHomeStack()
+                || task.getTopAppWindowToken() != mAppToken) {
+            // Don't save surfaces for home stack apps. These usually resume and draw
+            // first frame very fast. Saving surfaces are mostly a waste of memory.
+            // Don't save if the window is not the topmost window.
+            return false;
+        }
+
+        return mAppToken.shouldSaveSurface();
+    }
+
     @Override
     public boolean isDefaultDisplay() {
         final DisplayContent displayContent = getDisplayContent();
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index ecc1f2c..aa242f1 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -38,7 +38,6 @@
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.os.Debug;
 import android.os.RemoteException;
@@ -283,9 +282,8 @@
         }
         mTransformation.clear();
         final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
-        if (false && DEBUG_ANIM) Slog.v(
-            TAG, "Stepped animation in " + this +
-            ": more=" + more + ", xform=" + mTransformation);
+        if (false && DEBUG_ANIM) Slog.v(TAG, "Stepped animation in " + this + ": more=" + more
+                + ", xform=" + mTransformation);
         return more;
     }
 
@@ -526,6 +524,12 @@
             Slog.v(TAG, "Finishing drawing window " + mWin + ": mDrawState="
                     + drawStateToString());
         }
+        if (mWin.mAppToken != null) {
+            // App has drawn something to its windows, we're no longer animating with
+            // the saved surfaces. If the user exits now, we only want to save again
+            // if allDrawn is true.
+            mWin.mAppToken.mAnimatingWithSavedSurface = false;
+        }
         if (mDrawState == DRAW_PENDING) {
             if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
                 Slog.v(TAG, "finishDrawingLocked: mDrawState=COMMIT_DRAW_PENDING " + this + " in "
@@ -536,6 +540,7 @@
             mDrawState = COMMIT_DRAW_PENDING;
             return true;
         }
+
         return false;
     }
 
@@ -555,7 +560,8 @@
         mDrawState = READY_TO_SHOW;
         boolean result = false;
         final AppWindowToken atoken = mWin.mAppToken;
-        if (atoken == null || atoken.allDrawn || mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
+        if (atoken == null || atoken.allDrawn || atoken.mAnimatingWithSavedSurface ||
+                mWin.mAttrs.type == TYPE_APPLICATION_STARTING) {
             result = performShowLocked();
         }
         if (mDestroyPreservedSurfaceUponRedraw && result) {
@@ -996,12 +1002,16 @@
     }
 
     void destroySurfaceLocked() {
-        if (mWin.mAppToken != null && mWin == mWin.mAppToken.startingWindow) {
-            mWin.mAppToken.startingDisplayed = false;
+        final AppWindowToken wtoken = mWin.mAppToken;
+        if (wtoken != null) {
+            wtoken.mHasSavedSurface = false;
+            wtoken.mAnimatingWithSavedSurface = false;
+            if (mWin == wtoken.startingWindow) {
+                wtoken.startingDisplayed = false;
+            }
         }
 
         if (mSurfaceControl != null) {
-
             int i = mWin.mChildWindows.size();
             while (i > 0) {
                 i--;
@@ -1428,7 +1438,7 @@
         // living in a different stack. If we suddenly crop it to the new stack bounds, it might
         // get cut off. We don't want it to happen, so we let it ignore the stack bounds until it
         // gets removed. The window that will replace it will abide them.
-        if (appToken != null && appToken.mCropWindowsToStack && !appToken.mReplacingWindow) {
+        if (appToken != null && appToken.mCropWindowsToStack && !appToken.mWillReplaceWindow) {
             TaskStack stack = w.getTask().mStack;
             stack.getBounds(mTmpStackBounds);
             // When we resize we use the big surface approach, which means we can't trust the
@@ -1808,8 +1818,6 @@
                     + Debug.getCallers(3));
         }
         if (mDrawState == READY_TO_SHOW && mWin.isReadyForDisplayIgnoringKeyguard()) {
-            if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION)
-                WindowManagerService.logSurface(mWin, "SHOW (performShowLocked)", null);
             if (DEBUG_VISIBILITY || (DEBUG_STARTING_WINDOW &&
                     mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING)) {
                 Slog.v(TAG, "Showing " + this
@@ -1856,8 +1864,7 @@
                 }
             }
 
-            if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING
-                    && mWin.mAppToken != null) {
+            if (mWin.mAttrs.type != TYPE_APPLICATION_STARTING && mWin.mAppToken != null) {
                 mWin.mAppToken.firstWindowDrawn = true;
 
                 if (mWin.mAppToken.startingData != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 247562f..aca0f5b 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -17,6 +17,7 @@
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.WindowManagerService.DEBUG;
 import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT_REPEATS;
@@ -111,13 +112,34 @@
     private int mPreferredModeId = 0;
 
     private boolean mTraversalScheduled;
+    private int mDeferDepth = 0;
 
     public WindowSurfacePlacer(WindowManagerService service) {
         mService = service;
         mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
     }
 
+    /**
+     * See {@link WindowManagerService#deferSurfaceLayout()}
+     */
+    void deferLayout() {
+        mDeferDepth++;
+    }
+
+    /**
+     * See {@link WindowManagerService#continueSurfaceLayout()}
+     */
+    void continueLayout() {
+        mDeferDepth--;
+        if (mDeferDepth <= 0) {
+            performSurfacePlacement();
+        }
+    }
+
     final void performSurfacePlacement() {
+        if (mDeferDepth > 0) {
+            return;
+        }
         int loopCount = 6;
         do {
             mTraversalScheduled = false;
@@ -340,6 +362,10 @@
                 // Don't remove this window until rotation has completed.
                 continue;
             }
+            // Discard the saved surface if window size is changed, it can't be reused.
+            if (win.mAppToken != null) {
+                win.mAppToken.destroySavedSurfaces();
+            }
             win.reportResized();
             mService.mResizingWindows.remove(i);
         }
@@ -371,7 +397,9 @@
                 if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
                     wallpaperDestroyed = true;
                 }
-                win.mWinAnimator.destroySurfaceLocked();
+                if (!win.shouldSaveSurface()) {
+                    win.mWinAnimator.destroySurfaceLocked();
+                }
             } while (i > 0);
             mService.mDestroySurface.clear();
         }
@@ -1147,14 +1175,26 @@
             for (int j = 0; j < windowsCount; j++) {
                 appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
             }
-            mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    ">>> OPEN TRANSACTION handleAppTransitionReadyLocked()");
+            SurfaceControl.openTransaction();
+            try {
+                mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            } finally {
+                SurfaceControl.closeTransaction();
+                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                        "<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
+            }
             mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
             int topOpeningLayer = 0;
             if (animLp != null) {
                 int layer = -1;
                 for (int j = 0; j < wtoken.windows.size(); j++) {
-                    WindowState win = wtoken.windows.get(j);
+                    final WindowState win = wtoken.windows.get(j);
+                    // Clearing the mExiting flag before entering animation. It will be set
+                    // to true if app window is removed, or window relayout to invisible.
+                    win.mExiting = false;
                     if (win.mWinAnimator.mAnimLayer > layer) {
                         layer = win.mWinAnimator.mAnimLayer;
                     }
@@ -1165,6 +1205,8 @@
                 }
             }
             createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+
+            wtoken.restoreSavedSurfaces();
         }
 
         AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
@@ -1210,6 +1252,10 @@
                         + wtoken.allDrawn + " startingDisplayed="
                         + wtoken.startingDisplayed + " startingMoved="
                         + wtoken.startingMoved);
+
+                if (wtoken.mHasSavedSurface || wtoken.mAnimatingWithSavedSurface) {
+                    continue;
+                }
                 if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
                     return false;
                 }
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 89b2a47..01acdef 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -414,12 +414,9 @@
         return NO_ERROR;
     }
     if (Surface::isValid(connection.mSurface)) {
-        connection.mSurface.clear();
-    }
-    if (connection.mSurface != NULL) {
         connection.mSurface->setSidebandStream(NULL);
-        connection.mSurface.clear();
     }
+    connection.mSurface.clear();
     if (connection.mThread != NULL) {
         connection.mThread->shutdown();
         connection.mThread.clear();
@@ -616,6 +613,9 @@
         return BAD_VALUE;
     }
     sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
+    if (!Surface::isValid(surface)) {
+        return BAD_VALUE;
+    }
     return tvInputHal->addOrUpdateStream(deviceId, streamId, surface);
 }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 8385685..b4c8f96 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.devicepolicy;
 
+import com.google.android.collect.Sets;
+
 import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -88,6 +90,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.os.storage.StorageManager;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsInternal;
@@ -183,8 +186,6 @@
     private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
     private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
 
-    private static final boolean DBG = false;
-
     private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
     private static final String ATTR_SETUP_COMPLETE = "setup-complete";
     private static final String ATTR_PERMISSION_POLICY = "permission-policy";
@@ -274,6 +275,7 @@
     final Injector mInjector;
     final IPackageManager mIPackageManager;
     final UserManager mUserManager;
+    final UserManagerInternal mUserManagerInternal;
 
     final LocalService mLocalService;
 
@@ -357,8 +359,10 @@
                     getSendingUserId());
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
-                if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
-                        + action + " for user " + userHandle);
+                if (VERBOSE_LOG) {
+                    Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+                            + action + " for user " + userHandle);
+                }
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
@@ -1014,7 +1018,7 @@
 
     private void handlePackagesChanged(String packageName, int userHandle) {
         boolean removed = false;
-        if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
+        if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
         synchronized (this) {
             for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -1079,6 +1083,10 @@
             return UserManager.get(mContext);
         }
 
+        UserManagerInternal getUserManagerInternal() {
+            return LocalServices.getService(UserManagerInternal.class);
+        }
+
         NotificationManager getNotificationManager() {
             return mContext.getSystemService(NotificationManager.class);
         }
@@ -1233,6 +1241,7 @@
         mOwners = Preconditions.checkNotNull(injector.newOwners());
 
         mUserManager = Preconditions.checkNotNull(injector.getUserManager());
+        mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
 
         mLocalService = new LocalService();
@@ -1327,10 +1336,13 @@
         synchronized (this) {
             mOwners.load();
             findOwnerComponentIfNecessaryLocked();
+            migrateUserRestrictionsIfNecessaryLocked();
 
             // TODO PO may not have a class name either due to b/17652534.  Address that too.
 
             updateDeviceOwnerLocked();
+
+            // TODO Notify UM to update restrictions (?)
         }
     }
 
@@ -1350,14 +1362,113 @@
         if (doComponent == null) {
             Slog.e(LOG_TAG, "Device-owner isn't registered as device-admin");
         } else {
-            mOwners.setDeviceOwner(
+            mOwners.setDeviceOwnerWithRestrictionsMigrated(
                     doComponent,
                     mOwners.getDeviceOwnerName(),
-                    mOwners.getDeviceOwnerUserId());
+                    mOwners.getDeviceOwnerUserId(),
+                    !mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
             mOwners.writeDeviceOwner();
+            if (VERBOSE_LOG) {
+                Log.v(LOG_TAG, "Device owner component filled in");
+            }
         }
     }
 
+    /**
+     * We didn't use to persist user restrictions for each owners but only persisted in user
+     * manager.
+     */
+    private void migrateUserRestrictionsIfNecessaryLocked() {
+        boolean migrated = false;
+        // Migrate for the DO.  Basically all restrictions should be considered to be set by DO,
+        // except for the "system controlled" ones.
+        if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) {
+            if (VERBOSE_LOG) {
+                Log.v(LOG_TAG, "Migrating DO user restrictions");
+            }
+            migrated = true;
+
+            // Migrate user 0 restrictions to DO, except for "system" restrictions.
+            final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
+
+            migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin,
+                    /* exceptionList =*/ UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS);
+
+            mOwners.setDeviceOwnerUserRestrictionsMigrated();
+        }
+
+        // Migrate for POs.  We have a few more exceptions.
+        final Set<String> normalExceptionList = Sets.newArraySet(
+                UserManager.DISALLOW_OUTGOING_CALLS,
+                UserManager.DISALLOW_SMS);
+        normalExceptionList.addAll(UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS);
+
+        final Set<String> managedExceptionList = new ArraySet<>(normalExceptionList.size() + 1);
+        managedExceptionList.addAll(normalExceptionList);
+        managedExceptionList.add(UserManager.DISALLOW_WALLPAPER);
+
+        for (UserInfo ui : mUserManager.getUsers()) {
+            final int userId = ui.id;
+            if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) {
+                if (userId != UserHandle.USER_SYSTEM) {
+                    if (VERBOSE_LOG) {
+                        Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId);
+                    }
+                    migrated = true;
+
+                    final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId);
+
+                    final Set<String> exceptionList =
+                            ui.isManagedProfile() ? managedExceptionList : normalExceptionList;
+
+                    migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin,
+                            exceptionList);
+                }
+
+                mOwners.setProfileOwnerUserRestrictionsMigrated(userId);
+            }
+        }
+        if (VERBOSE_LOG && migrated) {
+            Log.v(LOG_TAG, "User restrictions migrated.");
+        }
+    }
+
+    private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin,
+            Set<String> exceptionList) {
+        final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions(
+                user.getIdentifier());
+
+        final Bundle newSystemRestrictions = new Bundle();
+        final Bundle newOwnerRestrictions = new Bundle();
+
+        for (String key : origRestrictions.keySet()) {
+            if (!origRestrictions.getBoolean(key)) {
+                continue;
+            }
+            if (exceptionList.contains(key)) {
+                newSystemRestrictions.putBoolean(key, true);
+            } else {
+                newOwnerRestrictions.putBoolean(key, true);
+            }
+        }
+
+        if (VERBOSE_LOG) {
+            Log.v(LOG_TAG, "origRestrictions=" + origRestrictions);
+            Log.v(LOG_TAG, "newSystemRestrictions=" + newSystemRestrictions);
+            Log.v(LOG_TAG, "newOwnerRestrictions=" + newOwnerRestrictions);
+        }
+        mUserManagerInternal.setBaseUserRestrictionsByDpmsForMigration(user.getIdentifier(),
+                newSystemRestrictions);
+
+        if (admin != null) {
+            admin.ensureUserRestrictions().clear();
+            admin.ensureUserRestrictions().putAll(newOwnerRestrictions);
+        } else {
+            Slog.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier());
+        }
+        saveSettingsLocked(user.getIdentifier());
+    }
+
     private ComponentName findAdminComponentWithPackageLocked(String packageName, int userId) {
         final DevicePolicyData policy = getUserData(userId);
         final int n = policy.mAdminList.size();
@@ -1373,7 +1484,7 @@
                 nFound++;
             }
         }
-        if (nFound > 0) {
+        if (nFound > 1) {
             Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
         }
         return found;
@@ -1636,6 +1747,9 @@
                 ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
                 : new File(mInjector.environmentGetUserSystemDirectory(userHandle),
                         DEVICE_POLICIES_XML).getAbsolutePath();
+        if (VERBOSE_LOG) {
+            Log.v(LOG_TAG, "Opening " + base);
+        }
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
@@ -1808,7 +1922,8 @@
                     try {
                         DeviceAdminInfo dai = findAdmin(
                                 ComponentName.unflattenFromString(name), userHandle);
-                        if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
+                        if (VERBOSE_LOG
+                                && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
                                 != userHandle)) {
                             Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
                                     + dai.getActivityInfo().applicationInfo.uid + " for user "
@@ -1988,8 +2103,10 @@
             long token = mInjector.binderClearCallingIdentity();
             try {
                 String value = cameraDisabled ? "1" : "0";
-                if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
-                        + cameraPropertyForUser + "] = " + value);
+                if (VERBOSE_LOG) {
+                    Slog.v(LOG_TAG, "Change in camera state ["
+                            + cameraPropertyForUser + "] = " + value);
+                }
                 mInjector.systemPropertiesSet(cameraPropertyForUser, value);
             } finally {
                 mInjector.binderRestoreCallingIdentity(token);
@@ -4513,8 +4630,10 @@
         }
         UserHandle callingUser = mInjector.binderGetCallingUserHandle();
         // Check if this is the profile owner who is calling
-        getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+        final ActiveAdmin admin =
+                getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         synchronized (this) {
+            admin.userRestrictions = null;
             clearUserPoliciesLocked(callingUser);
             final int userId = callingUser.getIdentifier();
             mOwners.removeProfileOwner(userId);
@@ -4533,38 +4652,19 @@
 
         final long ident = mInjector.binderClearCallingIdentity();
         try {
-            clearUserRestrictions(userHandle);
             mIPackageManager.updatePermissionFlagsForAllApps(
                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
                     0  /* flagValues */, userHandle.getIdentifier());
+            // TODO This will not revert audio mute restrictions if they were set.  b/24981972
+            synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
+                mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle.getIdentifier());
+            }
         } catch (RemoteException re) {
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
-
-    private void clearUserRestrictions(UserHandle userHandle) {
-        Bundle userRestrictions = mUserManager.getUserRestrictions();
-        mUserManager.setUserRestrictions(new Bundle(), userHandle);
-        if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
-            try {
-                mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(),
-                        userHandle.getIdentifier());
-            } catch (RemoteException e) {
-                // Not much we can do here.
-            }
-        }
-        if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
-            try {
-                mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(),
-                        userHandle.getIdentifier());
-            } catch (RemoteException e) {
-                // Not much we can do here.
-            }
-        }
-    }
-
     @Override
     public boolean hasUserSetupCompleted() {
         return hasUserSetupCompleted(UserHandle.getCallingUserId());
@@ -5503,95 +5603,123 @@
     }
 
     @Override
-    public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+    public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
         Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = mInjector.userHandleGetCallingUserId();
         final UserHandle user = new UserHandle(userHandle);
-        synchronized (this) {
-            ActiveAdmin activeAdmin =
-                    getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            boolean isDeviceOwner = isDeviceOwner(who);
-            if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM
-                    && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
-                throw new SecurityException("Profile owners cannot set user restriction " + key);
-            }
-            if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
-                throw new SecurityException("User restriction " + key + " cannot be changed");
-            }
-            boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
+        synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
+            synchronized (this) {
+                ActiveAdmin activeAdmin =
+                        getActiveAdminForCallerLocked(who,
+                                DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+                boolean isDeviceOwner = isDeviceOwner(who);
+                if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM
+                        && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
+                    throw new SecurityException(
+                            "Profile owners cannot set user restriction " + key);
+                }
+                if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
+                    throw new SecurityException("User restriction " + key + " cannot be changed");
+                }
 
-            long id = mInjector.binderClearCallingIdentity();
-            try {
-                if (enabled && !alreadyRestricted) {
-                    if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
-                        mInjector.getIAudioService()
-                                .setMicrophoneMute(true, mContext.getPackageName(), userHandle);
-                    } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        mInjector.getIAudioService()
-                                .setMasterMute(true, 0, mContext.getPackageName(), userHandle);
-                    } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
-                        mInjector.settingsSecurePutIntForUser(
-                                Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
-                                userHandle);
-                    } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
-                        mInjector.settingsSecurePutIntForUser(
-                                Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF,
-                                userHandle);
-                        mInjector.settingsSecurePutStringForUser(
-                                Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
-                                userHandle);
-                    } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
-                        // Only disable adb if changing for system user, since it is global
-                        // TODO: should this be admin user?
-                        if (userHandle == UserHandle.USER_SYSTEM) {
+                final long id = mInjector.binderClearCallingIdentity();
+                try {
+                    // Original value.
+                    final boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
+
+                    // Save the restriction to ActiveAdmin.
+                    // TODO When DO sets a restriction, it'll always be treated as device-wide.
+                    // If there'll be a policy that can be set by both, we'll need scoping support,
+                    // and need to have another Bundle in DO active admin to hold restrictions as
+                    // PO.
+                    activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
+                    saveSettingsLocked(userHandle);
+
+                    // Tell UserManager the new value.  Note this needs to be done before calling
+                    // into AudioService, because AS will check AppOps that'll be updated by UM.
+                    if (isDeviceOwner) {
+                        mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL();
+                    } else {
+                        mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle);
+                    }
+
+                    // New value.
+                    final boolean enabled = mUserManager.hasUserRestriction(key, user);
+
+                    // TODO The rest of the code should move to UserManagerService.
+
+                    if (enabled && !alreadyRestricted) {
+                        if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
+                            mInjector.getIAudioService()
+                                    .setMicrophoneMute(true, mContext.getPackageName(), userHandle);
+                        } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
+                            mInjector.getIAudioService()
+                                    .setMasterMute(true, 0, mContext.getPackageName(), userHandle);
+                        } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
+                            mInjector.settingsSecurePutIntForUser(
+                                    Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
+                                    userHandle);
+                        } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
+                            mInjector.settingsSecurePutIntForUser(
+                                    Settings.Secure.LOCATION_MODE,
+                                    Settings.Secure.LOCATION_MODE_OFF,
+                                    userHandle);
+                            mInjector.settingsSecurePutStringForUser(
+                                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
+                                    userHandle);
+                        } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
+                            // Only disable adb if changing for system user, since it is global
+                            // TODO: should this be admin user?
+                            if (userHandle == UserHandle.USER_SYSTEM) {
+                                mInjector.settingsGlobalPutStringForUser(
+                                        Settings.Global.ADB_ENABLED, "0", userHandle);
+                            }
+                        } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
                             mInjector.settingsGlobalPutStringForUser(
-                                    Settings.Global.ADB_ENABLED, "0", userHandle);
+                                    Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
+                                    userHandle);
+                            mInjector.settingsGlobalPutStringForUser(
+                                    Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
+                                    userHandle);
+                        } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
+                            mInjector.settingsSecurePutIntForUser(
+                                    Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
+                                    userHandle);
                         }
-                    } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
-                        mInjector.settingsGlobalPutStringForUser(
-                                Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
-                                userHandle);
-                        mInjector.settingsGlobalPutStringForUser(
-                                Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
-                                userHandle);
-                    } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
-                        mInjector.settingsSecurePutIntForUser(
-                                Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
-                                userHandle);
                     }
-                }
-                mUserManager.setUserRestriction(key, enabled, user);
-                activeAdmin.ensureUserRestrictions().putBoolean(key, enabled);
-                saveSettingsLocked(userHandle);
 
-                if (enabled != alreadyRestricted) {
-                    if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
-                        // Send out notifications however as some clients may want to reread the
-                        // value which actually changed due to a restriction having been applied.
-                        final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
-                        long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
-                        mInjector.systemPropertiesSet(property, Long.toString(version));
+                    if (enabled != alreadyRestricted) {
+                        if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
+                            // Send out notifications however as some clients may want to reread the
+                            // value which actually changed due to a restriction having been
+                            // applied.
+                            final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
+                            long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
+                            mInjector.systemPropertiesSet(property, Long.toString(version));
 
-                        final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
-                        Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
-                        mContext.getContentResolver().notifyChange(url, null, true, userHandle);
+                            final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
+                            Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
+                            mContext.getContentResolver().notifyChange(url, null, true, userHandle);
+                        }
                     }
-                }
-                if (!enabled && alreadyRestricted) {
-                    if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
-                        mInjector.getIAudioService()
-                                .setMicrophoneMute(false, mContext.getPackageName(), userHandle);
-                    } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        mInjector.getIAudioService()
-                                .setMasterMute(false, 0, mContext.getPackageName(), userHandle);
+                    if (!enabled && alreadyRestricted) {
+                        if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
+                            mInjector.getIAudioService()
+                                    .setMicrophoneMute(false, mContext.getPackageName(),
+                                            userHandle);
+                        } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
+                            mInjector.getIAudioService()
+                                    .setMasterMute(false, 0, mContext.getPackageName(), userHandle);
+                        }
                     }
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
+                } finally {
+                    mInjector.binderRestoreCallingIdentity(id);
                 }
-            } catch (RemoteException re) {
-                Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(id);
+
+                sendChangedNotification(userHandle);
             }
-            sendChangedNotification(userHandle);
         }
     }
 
@@ -5650,7 +5778,7 @@
             long id = mInjector.binderClearCallingIdentity();
 
             try {
-                if (DBG) {
+                if (VERBOSE_LOG) {
                     Slog.v(LOG_TAG, "installing " + packageName + " for "
                             + userId);
                 }
@@ -5705,7 +5833,9 @@
                         0, // no flags
                         primaryUser.id);
 
-                if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+                if (VERBOSE_LOG) {
+                    Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
+                }
                 int numberOfAppsInstalled = 0;
                 if (activitiesToEnable != null) {
                     for (ResolveInfo info : activitiesToEnable) {
@@ -6275,7 +6405,8 @@
         }
     }
 
-    private final class LocalService extends DevicePolicyManagerInternal {
+    @VisibleForTesting
+    final class LocalService extends DevicePolicyManagerInternal {
         private List<OnCrossProfileWidgetProvidersChangeListener> mWidgetProviderListeners;
 
         @Override
@@ -6322,6 +6453,30 @@
             }
         }
 
+        @Override
+        public Bundle getComposedUserRestrictions(int userId, Bundle inBundle) {
+            synchronized (DevicePolicyManagerService.this) {
+                final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+                final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+
+                final Bundle deviceOwnerRestrictions =
+                        deviceOwner == null ? null : deviceOwner.userRestrictions;
+                final Bundle profileOwnerRestrictions =
+                        profileOwner == null ? null : profileOwner.userRestrictions;
+
+                if (deviceOwnerRestrictions == null && profileOwnerRestrictions == null) {
+                    // No restrictions to merge.
+                    return inBundle;
+                }
+
+                final Bundle composed = new Bundle(inBundle);
+                UserRestrictionsUtils.merge(composed, deviceOwnerRestrictions);
+                UserRestrictionsUtils.merge(composed, profileOwnerRestrictions);
+
+                return composed;
+            }
+        }
+
         private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
             final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
             synchronized (DevicePolicyManagerService.this) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 799267d..12b3775 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -30,7 +30,6 @@
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
-import com.android.internal.util.Preconditions;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -75,6 +74,7 @@
     private static final String ATTR_PACKAGE = "package";
     private static final String ATTR_COMPONENT_NAME = "component";
     private static final String ATTR_USERID = "userId";
+    private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
 
     private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
 
@@ -155,7 +155,16 @@
             Slog.e(TAG, "Invalid user id for device owner user: " + userId);
             return;
         }
-        mDeviceOwner = new OwnerInfo(ownerName, admin);
+        // For a newly set DO, there's no need for migration.
+        setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
+                /* userRestrictionsMigrated =*/ true);
+    }
+
+    // Note this should be only called during migration.  Normally when DO is set,
+    // userRestrictionsMigrated should always be true.
+    void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
+            boolean userRestrictionsMigrated) {
+        mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated);
         mDeviceOwnerUserId = userId;
     }
 
@@ -165,7 +174,9 @@
     }
 
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
-        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
+        // For a newly set PO, there's no need for migration.
+        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
+                /* userRestrictionsMigrated =*/ true));
     }
 
     void removeProfileOwner(int userId) {
@@ -207,6 +218,38 @@
         return mDeviceOwner != null;
     }
 
+    /**
+     * @return true if user restrictions need to be migrated for DO.
+     */
+    boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
+        return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
+    }
+
+    /**
+     * @return true if user restrictions need to be migrated for PO.
+     */
+    boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null && !profileOwner.userRestrictionsMigrated;
+    }
+
+    /** Sets the user restrictions migrated flag, and also writes to the file. */
+    void setDeviceOwnerUserRestrictionsMigrated() {
+        if (mDeviceOwner != null) {
+            mDeviceOwner.userRestrictionsMigrated = true;
+        }
+        writeDeviceOwner();
+    }
+
+    /** Sets the user restrictions migrated flag, and also writes to the file.  */
+    void setProfileOwnerUserRestrictionsMigrated(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        if (profileOwner != null) {
+            profileOwner.userRestrictionsMigrated = true;
+        }
+        writeProfileOwner(userId);
+    }
+
     private boolean readLegacyOwnerFile(File file) {
         if (!file.exists()) {
             // Already migrated or the device has no owners.
@@ -226,7 +269,8 @@
                 if (tag.equals(TAG_DEVICE_OWNER)) {
                     String name = parser.getAttributeValue(null, ATTR_NAME);
                     String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    mDeviceOwner = new OwnerInfo(name, packageName);
+                    mDeviceOwner = new OwnerInfo(name, packageName,
+                            /* userRestrictionsMigrated =*/ false);
                     mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
                 } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
                     // Deprecated tag
@@ -241,7 +285,8 @@
                         ComponentName admin = ComponentName.unflattenFromString(
                                 profileOwnerComponentStr);
                         if (admin != null) {
-                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin);
+                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
+                                /* userRestrictionsMigrated =*/ false);
                         } else {
                             // This shouldn't happen but switch from package name -> component name
                             // might have written bad device owner files. b/17652534
@@ -250,7 +295,8 @@
                         }
                     }
                     if (profileOwnerInfo == null) {
-                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
+                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
+                                /* userRestrictionsMigrated =*/ false);
                     }
                     mProfileOwners.put(userId, profileOwnerInfo);
                 } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
@@ -503,21 +549,24 @@
         }
     }
 
-    private static class OwnerInfo {
+    static class OwnerInfo {
         public final String name;
         public final String packageName;
         public final ComponentName admin;
+        public boolean userRestrictionsMigrated;
 
-        public OwnerInfo(String name, String packageName) {
+        public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated) {
             this.name = name;
             this.packageName = packageName;
             this.admin = new ComponentName(packageName, "");
+            this.userRestrictionsMigrated = userRestrictionsMigrated;
         }
 
-        public OwnerInfo(String name, ComponentName admin) {
+        public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated) {
             this.name = name;
             this.admin = admin;
             this.packageName = admin.getPackageName();
+            this.userRestrictionsMigrated = userRestrictionsMigrated;
         }
 
         public void writeToXml(XmlSerializer out, String tag) throws IOException {
@@ -529,6 +578,8 @@
             if (admin != null) {
                 out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
             }
+            out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
+                    String.valueOf(userRestrictionsMigrated));
             out.endTag(null, tag);
         }
 
@@ -537,12 +588,16 @@
             final String name = parser.getAttributeValue(null, ATTR_NAME);
             final String componentName =
                     parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+            final String userRestrictionsMigratedStr =
+                    parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED);
+            final boolean userRestrictionsMigrated =
+                    ("true".equals(userRestrictionsMigratedStr));
 
             // Has component name?  If so, return [name, component]
             if (componentName != null) {
                 final ComponentName admin = ComponentName.unflattenFromString(componentName);
                 if (admin != null) {
-                    return new OwnerInfo(name, admin);
+                    return new OwnerInfo(name, admin, userRestrictionsMigrated);
                 } else {
                     // This shouldn't happen but switch from package name -> component name
                     // might have written bad device owner files. b/17652534
@@ -552,7 +607,7 @@
             }
 
             // Else, build with [name, package]
-            return new OwnerInfo(name, packageName);
+            return new OwnerInfo(name, packageName, userRestrictionsMigrated);
         }
 
         public void dump(String prefix, PrintWriter pw) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 1ec1a46..e32af5c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -438,7 +438,6 @@
         InputManagerService inputManager = null;
         TelephonyRegistry telephonyRegistry = null;
         ConsumerIrService consumerIr = null;
-        AudioService audioService = null;
         MmsServiceBroker mmsService = null;
         EntropyMixer entropyMixer = null;
 
@@ -857,12 +856,7 @@
             }
 
             traceBeginAndSlog("StartAudioService");
-            try {
-                audioService = new AudioService(context);
-                ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
-            } catch (Throwable e) {
-                reportWtf("starting Audio Service", e);
-            }
+            mSystemServiceManager.startService(AudioService.Lifecycle.class);
             Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNonCoreServices) {
@@ -1163,7 +1157,6 @@
         final InputManagerService inputManagerF = inputManager;
         final TelephonyRegistry telephonyRegistryF = telephonyRegistry;
         final MediaRouterService mediaRouterF = mediaRouter;
-        final AudioService audioServiceF = audioService;
         final MmsServiceBroker mmsServiceF = mmsService;
 
         // We now tell the activity manager it is okay to run third party
@@ -1234,13 +1227,7 @@
                     reportWtf("making Connectivity Service ready", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAudioServiceReady");
-                try {
-                    if (audioServiceF != null) audioServiceF.systemReady();
-                } catch (Throwable e) {
-                    reportWtf("Notifying AudioService running", e);
-                }
-                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 28cb114..c9efc69 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -417,9 +417,10 @@
                 encap, mTransactionId, getSecs(), clientAddress,
                 DO_UNICAST, mHwAddr, requestedAddress,
                 serverAddress, REQUESTED_PARAMS, null);
+        String serverStr = (serverAddress != null) ? serverAddress.getHostAddress() : null;
         String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
                              " request=" + requestedAddress.getHostAddress() +
-                             " to=" + serverAddress.getHostAddress();
+                             " serverid=" + serverStr;
         return transmitPacket(packet, description, to);
     }
 
@@ -822,7 +823,8 @@
         public void enter() {
             super.enter();
             if (!setIpAddress(mDhcpLease.ipAddress) ||
-                    !connectUdpSock((mDhcpLease.serverAddress))) {
+                    (mDhcpLease.serverAddress != null &&
+                            !connectUdpSock((mDhcpLease.serverAddress)))) {
                 notifyFailure();
                 // There's likely no point in going into DhcpInitState here, we'll probably just
                 // repeat the transaction, get the same IP address as before, and fail.
@@ -878,11 +880,15 @@
         }
 
         protected boolean sendPacket() {
+            // Not specifying a SERVER_IDENTIFIER option is a violation of RFC 2131, but...
+            // http://b/25343517 . Try to make things work anyway by using broadcast renews.
+            Inet4Address to = (mDhcpLease.serverAddress != null) ?
+                    mDhcpLease.serverAddress : INADDR_BROADCAST;
             return sendRequestPacket(
                     (Inet4Address) mDhcpLease.ipAddress.getAddress(),  // ciaddr
                     INADDR_ANY,                                        // DHCP_REQUESTED_IP
-                    INADDR_ANY,                                        // DHCP_SERVER_IDENTIFIER
-                    (Inet4Address) mDhcpLease.serverAddress);          // packet destination address
+                    null,                                              // DHCP_SERVER_IDENTIFIER
+                    to);                                               // packet destination address
         }
 
         protected void receivePacket(DhcpPacket packet) {
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 53f55cd..88155f7 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -403,7 +403,6 @@
 
     // TODO: simply the number of objects by making this extend Thread.
     private final class NetlinkSocketObserver implements Runnable {
-        private static final String TAG = "NetlinkSocketObserver";
         private NetlinkSocket mSocket;
 
         @Override
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
new file mode 100644
index 0000000..9564969
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.android.frameworks.servicestests" />
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="10" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="11" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" />
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
new file mode 100644
index 0000000..48cb814
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+    <admin name="com.google.android.gms/com.google.android.gms.mdm.receivers.MdmDeviceAdminReceiver">
+    </admin>
+    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+    </admin>
+</policies>
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
new file mode 100644
index 0000000..6b53840
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
+    </admin>
+</policies>
diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
new file mode 100644
index 0000000..2bcc5d4
--- /dev/null
+++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+    <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3">
+    </admin>
+</policies>
diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
index 90b4f43..c12f978 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java
@@ -876,11 +876,12 @@
     }
 
     private void expectSystemReady() throws Exception {
-        mAlarmManager.remove(isA(PendingIntent.class));
+        mAlarmManager.remove(isA(PendingIntent.class), null);
         expectLastCall().anyTimes();
 
-        mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
-                anyInt(), isA(PendingIntent.class), isA(WorkSource.class),
+        mAlarmManager.set(getContext().getPackageName(),
+                eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(),
+                anyInt(), isA(PendingIntent.class), null, null, isA(WorkSource.class),
                 isA(AlarmManager.AlarmClockInfo.class));
         expectLastCall().atLeastOnce();
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
new file mode 100644
index 0000000..dfa9f8f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.devicepolicy;
+
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
+import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
+
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Pair;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.when;
+
+public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
+    private DpmMockContext mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mContext = getContext();
+
+        when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
+                .thenReturn(true);
+    }
+
+    public void testMigration() throws Exception {
+        final File user10dir = mMockContext.addUser(10, 0);
+        final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE);
+        final File user12dir = mMockContext.addUser(12, 0);
+
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+        setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
+        setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456));
+
+        // Create the legacy owners & policies file.
+        DpmTestUtils.writeToFile(
+                (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
+                DpmTestUtils.readAsset(mRealTestContext,
+                        "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml"));
+
+        DpmTestUtils.writeToFile(
+                (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
+                DpmTestUtils.readAsset(mRealTestContext,
+                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml"));
+
+        DpmTestUtils.writeToFile(
+                (new File(user10dir, "device_policies.xml")).getAbsoluteFile(),
+                DpmTestUtils.readAsset(mRealTestContext,
+                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml"));
+        DpmTestUtils.writeToFile(
+                (new File(user11dir, "device_policies.xml")).getAbsoluteFile(),
+                DpmTestUtils.readAsset(mRealTestContext,
+                        "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml"));
+
+        // Set up UserManager
+        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
+                eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
+                UserManager.DISALLOW_ADD_USER,
+                UserManager.DISALLOW_RECORD_AUDIO));
+
+        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
+                eq(10))).thenReturn(DpmTestUtils.newRestrictions(
+                UserManager.DISALLOW_REMOVE_USER,
+                UserManager.DISALLOW_SMS,
+                UserManager.DISALLOW_OUTGOING_CALLS,
+                UserManager.DISALLOW_WALLPAPER,
+                UserManager.DISALLOW_RECORD_AUDIO));
+
+        when(mMockContext.userManagerInternal.getBaseUserRestrictions(
+                eq(11))).thenReturn(DpmTestUtils.newRestrictions(
+                UserManager.DISALLOW_REMOVE_USER,
+                UserManager.DISALLOW_SMS,
+                UserManager.DISALLOW_OUTGOING_CALLS,
+                UserManager.DISALLOW_WALLPAPER,
+                UserManager.DISALLOW_RECORD_AUDIO));
+
+        final Map<Integer, Bundle> newBaseRestrictions = new HashMap<>();
+
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                Integer userId = (Integer) invocation.getArguments()[0];
+                Bundle bundle = (Bundle) invocation.getArguments()[1];
+
+                newBaseRestrictions.put(userId, bundle);
+
+                return null;
+            }
+        }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration(
+                anyInt(), any(Bundle.class));
+
+        // Initialize DPM/DPMS and let it migrate the persisted information.
+        // (Need clearCallingIdentity() to pass permission checks.)
+
+        final DevicePolicyManagerServiceTestable dpms;
+
+        final long ident = mContext.binder.clearCallingIdentity();
+        try {
+            LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+            dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
+
+            dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
+            dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
+        } finally {
+            mContext.binder.restoreCallingIdentity(ident);
+        }
+
+        // Now all information should be migrated.
+        assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
+        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+        assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12));
+
+        // Check the new base restrictions.
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_RECORD_AUDIO
+                ),
+                newBaseRestrictions.get(UserHandle.USER_SYSTEM));
+
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_SMS,
+                        UserManager.DISALLOW_OUTGOING_CALLS,
+                        UserManager.DISALLOW_RECORD_AUDIO
+                ),
+                newBaseRestrictions.get(10));
+
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_SMS,
+                        UserManager.DISALLOW_OUTGOING_CALLS,
+                        UserManager.DISALLOW_WALLPAPER,
+                        UserManager.DISALLOW_RECORD_AUDIO
+                ),
+                newBaseRestrictions.get(11));
+
+        // Check the new owner restrictions.
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_ADD_USER
+                ),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions());
+
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_REMOVE_USER,
+                        UserManager.DISALLOW_WALLPAPER
+                ),
+                dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions());
+
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_REMOVE_USER
+                ),
+                dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index b109e7b..2c01b8a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -27,6 +27,7 @@
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.view.IWindowManager;
 
 import java.io.File;
@@ -107,6 +108,11 @@
         }
 
         @Override
+        UserManagerInternal getUserManagerInternal() {
+            return context.userManagerInternal;
+        }
+
+        @Override
         PowerManagerInternal getPowerManagerInternal() {
             return context.powerManagerInternal;
         }
@@ -153,7 +159,7 @@
 
         @Override
         String getDevicePolicyFilePathForSystemUser() {
-            return context.systemUserDataDir.getAbsolutePath();
+            return context.systemUserDataDir.getAbsolutePath() + "/";
         }
 
         @Override
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d6a60c7..727858b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -27,7 +27,6 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.Bundle;
@@ -70,9 +69,6 @@
     private DpmMockContext mContext;
     public DevicePolicyManager dpm;
     public DevicePolicyManagerServiceTestable dpms;
-    public ComponentName admin1;
-    public ComponentName admin2;
-    public ComponentName admin3;
 
     @Override
     protected void setUp() throws Exception {
@@ -85,10 +81,6 @@
 
         initializeDpms();
 
-        admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
-        admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
-        admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
-
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -113,67 +105,6 @@
         }
     }
 
-    private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) throws Exception {
-        setUpPackageManagerForAdmin(admin, packageUid,
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
-    }
-
-    private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
-            int enabledSetting) throws Exception {
-
-        // Set up queryBroadcastReceivers().
-
-        final Intent resolveIntent = new Intent();
-        resolveIntent.setComponent(admin);
-        final List<ResolveInfo> realResolveInfo =
-                mRealTestContext.getPackageManager().queryBroadcastReceivers(
-                        resolveIntent,
-                        PackageManager.GET_META_DATA);
-        assertNotNull(realResolveInfo);
-        assertEquals(1, realResolveInfo.size());
-
-        // We need to change AI, so set a clone.
-        realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
-
-        // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid;
-
-        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
-                MockUtils.checkIntentComponent(admin),
-                eq(PackageManager.GET_META_DATA
-                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(UserHandle.getUserId(packageUid)));
-
-        // Set up getApplicationInfo().
-
-        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
-                mRealTestContext.getPackageManager().getApplicationInfo(
-                        admin1.getPackageName(),
-                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
-
-        ai.enabledSetting = enabledSetting;
-        ai.uid = packageUid;
-
-        doReturn(ai).when(mContext.ipackageManager).getApplicationInfo(
-                eq(admin1.getPackageName()),
-                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(UserHandle.getUserId(packageUid)));
-
-        // Set up getPackageInfo().
-
-        final PackageInfo pi = DpmTestUtils.cloneParcelable(
-                mRealTestContext.getPackageManager().getPackageInfo(
-                        admin1.getPackageName(), 0));
-        assertTrue(pi.applicationInfo.flags != 0);
-
-        pi.applicationInfo.uid = packageUid;
-
-        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
-                eq(admin1.getPackageName()),
-                eq(0),
-                eq(UserHandle.getUserId(packageUid)));
-    }
-
     private void setUpUserManager() {
         // Emulate UserManager.set/getApplicationRestriction().
         final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
@@ -220,7 +151,7 @@
         assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
 
         // Check
-        assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
+        assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
     }
 
     public void testHasNoFeature() throws Exception {
@@ -743,6 +674,8 @@
         assertEquals("", dpms.getDeviceOwner().getClassName());
 
         // Then create a new DPMS to have it load the settings from files.
+        when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
+                .thenReturn(new Bundle());
         initializeDpms();
 
         // Now the DO component name is a full name.
@@ -802,32 +735,33 @@
         assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
                 UserHandle.USER_SYSTEM));
 
-        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_SMS));
-        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+        );
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS);
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
 
-        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_SMS));
-        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+        );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS);
 
-        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_SMS));
-        assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+        );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
 
-        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_SMS));
-        assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(),
+                dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
+        );
 
         // TODO Check inner calls.
         // TODO Make sure restrictions are written to the file.
@@ -836,42 +770,106 @@
     public void testSetUserRestriction_asPo() {
         setAsProfileOwner(admin1);
 
-        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
-        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(),
+                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                        .ensureUserRestrictions()
+        );
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
 
-        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
-        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
+                        UserManager.DISALLOW_OUTGOING_CALLS
+                ),
+                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                        .ensureUserRestrictions()
+        );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
 
-        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
-        assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(
+                        UserManager.DISALLOW_OUTGOING_CALLS
+                ),
+                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                        .ensureUserRestrictions()
+        );
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
 
-        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
-        assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
-                .ensureUserRestrictions()
-                .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions(),
+                dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
+                        .ensureUserRestrictions()
+        );
 
         // TODO Check inner calls.
         // TODO Make sure restrictions are written to the file.
     }
+
+    public void testGetComposedUserRestrictions_noDoNoPo() throws Exception {
+        final Bundle in = DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS);
+
+        Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
+                UserHandle.USER_SYSTEM, in);
+        assertTrue(in == actual);
+
+        actual = dpms.mLocalService.getComposedUserRestrictions(
+                DpmMockContext.CALLER_USER_HANDLE, in);
+        assertTrue(in == actual);
+    }
+
+    public void testGetComposedUserRestrictions() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+        // First, set DO.
+
+        // Call from a process on the system user.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // Make sure admin1 is installed on system user.
+        setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
+
+        // Call.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
+        assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
+                UserHandle.USER_SYSTEM));
+
+        dpm.addUserRestriction(admin1, "rest1");
+        dpm.addUserRestriction(admin1, "rest2");
+
+        // Set PO on CALLER_USER_HANDLE.
+        mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+        setAsProfileOwner(admin2);
+
+        dpm.addUserRestriction(admin2, "restA");
+        dpm.addUserRestriction(admin2, "restB");
+
+        final Bundle in = DpmTestUtils.newRestrictions("abc");
+
+        Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
+                UserHandle.USER_SYSTEM, in);
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
+                actual);
+
+        actual = dpms.mLocalService.getComposedUserRestrictions(
+                DpmMockContext.CALLER_USER_HANDLE, in);
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions("abc", "rest1", "rest2", "restA", "restB"),
+                actual);
+
+        actual = dpms.mLocalService.getComposedUserRestrictions(
+                DpmMockContext.CALLER_USER_HANDLE + 1, in);
+        DpmTestUtils.assertRestrictions(
+                DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
+                actual);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index d1b4835..cc337b0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -36,6 +36,7 @@
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.test.mock.MockContentResolver;
 import android.test.mock.MockContext;
 import android.view.IWindowManager;
@@ -203,6 +204,7 @@
     public final EnvironmentForMock environment;
     public final SystemPropertiesForMock systemProperties;
     public final UserManager userManager;
+    public final UserManagerInternal userManagerInternal;
     public final UserManagerForMock userManagerForMock;
     public final PowerManagerForMock powerManager;
     public final PowerManagerInternal powerManagerInternal;
@@ -233,6 +235,7 @@
         environment = mock(EnvironmentForMock.class);
         systemProperties= mock(SystemPropertiesForMock.class);
         userManager = mock(UserManager.class);
+        userManagerInternal = mock(UserManagerInternal.class);
         userManagerForMock = mock(UserManagerForMock.class);
         powerManager = mock(PowerManagerForMock.class);
         powerManagerInternal = mock(PowerManagerInternal.class);
@@ -257,6 +260,9 @@
 
         // System user is always running.
         setUserRunning(UserHandle.USER_SYSTEM, true);
+
+        // This method must return an object.
+        when(userManagerInternal.getUserRestrictionsLock()).thenReturn(new Object());
     }
 
     public File addUser(int userId, int flags) {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 63bf125..e11f3fb 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -16,10 +16,21 @@
 
 package com.android.server.devicepolicy;
 
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
 import android.test.AndroidTestCase;
 
 import java.io.File;
+import java.util.List;
+
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 
 public abstract class DpmTestBase extends AndroidTestCase {
     public static final String TAG = "DpmTest";
@@ -29,6 +40,10 @@
 
     public File dataDir;
 
+    public ComponentName admin1;
+    public ComponentName admin2;
+    public ComponentName admin3;
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -37,10 +52,77 @@
 
         mMockContext = new DpmMockContext(
                 mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data"));
+
+        admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
+        admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
+        admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
     }
 
     @Override
     public DpmMockContext getContext() {
         return mMockContext;
     }
+
+
+    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
+            throws Exception {
+        setUpPackageManagerForAdmin(admin, packageUid,
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+    }
+
+    protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
+            int enabledSetting) throws Exception {
+
+        // Set up queryBroadcastReceivers().
+
+        final Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(admin);
+        final List<ResolveInfo> realResolveInfo =
+                mRealTestContext.getPackageManager().queryBroadcastReceivers(
+                        resolveIntent,
+                        PackageManager.GET_META_DATA);
+        assertNotNull(realResolveInfo);
+        assertEquals(1, realResolveInfo.size());
+
+        // We need to change AI, so set a clone.
+        realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
+
+        // We need to rewrite the UID in the activity info.
+        realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid;
+
+        doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers(
+                MockUtils.checkIntentComponent(admin),
+                eq(PackageManager.GET_META_DATA
+                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(UserHandle.getUserId(packageUid)));
+
+        // Set up getApplicationInfo().
+
+        final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
+                mRealTestContext.getPackageManager().getApplicationInfo(
+                        admin.getPackageName(),
+                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
+
+        ai.enabledSetting = enabledSetting;
+        ai.uid = packageUid;
+
+        doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
+                eq(admin.getPackageName()),
+                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(UserHandle.getUserId(packageUid)));
+
+        // Set up getPackageInfo().
+
+        final PackageInfo pi = DpmTestUtils.cloneParcelable(
+                mRealTestContext.getPackageManager().getPackageInfo(
+                        admin.getPackageName(), 0));
+        assertTrue(pi.applicationInfo.flags != 0);
+
+        pi.applicationInfo.uid = packageUid;
+
+        doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo(
+                eq(admin.getPackageName()),
+                eq(0),
+                eq(UserHandle.getUserId(packageUid)));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
index 7506273..cceb2d2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
@@ -16,21 +16,35 @@
 
 package com.android.server.devicepolicy;
 
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+
+import android.content.Context;
+import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.Printer;
 
 import org.junit.Assert;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
-public class DpmTestUtils {
-    private DpmTestUtils() {
-    }
+import junit.framework.AssertionFailedError;
 
+public class DpmTestUtils extends AndroidTestCase {
     public static void clearDir(File dir) {
         if (dir.exists()) {
             Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
@@ -43,6 +57,44 @@
         return list == null ? 0 : list.size();
     }
 
+    public static Bundle newRestrictions(String... restrictions) {
+        final Bundle ret = new Bundle();
+        for (String restriction : restrictions) {
+            ret.putBoolean(restriction, true);
+        }
+        return ret;
+    }
+
+    public static void assertRestrictions(Bundle expected, Bundle actual) {
+        final ArrayList<String> elist;
+        if (expected == null) {
+            elist = null;
+        } else {
+            elist = Lists.newArrayList();
+            for (String key : expected.keySet()) {
+                if (expected.getBoolean(key)) {
+                    elist.add(key);
+                }
+            }
+            Collections.sort(elist);
+        }
+
+        final ArrayList<String> alist;
+        if (actual == null) {
+            alist = null;
+        } else {
+            alist = Lists.newArrayList();
+            for (String key : actual.keySet()) {
+                if (actual.getBoolean(key)) {
+                    alist.add(key);
+                }
+            }
+            Collections.sort(alist);
+        }
+
+        assertEquals(elist, alist);
+    }
+
     public static <T extends Parcelable> T cloneParcelable(T source) {
         Parcel p = Parcel.obtain();
         p.writeParcelable(source, 0);
@@ -58,4 +110,57 @@
             Log.i(DpmTestBase.TAG, x);
         }
     };
+
+    public static String readAsset(Context context, String assetPath) throws IOException {
+        final StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(
+                new InputStreamReader(
+                        context.getResources().getAssets().open(assetPath)))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                sb.append(line);
+                sb.append(System.lineSeparator());
+            }
+        }
+        return sb.toString();
+    }
+
+    public static void writeToFile(File path, String content)
+            throws IOException {
+        path.getParentFile().mkdirs();
+
+        try (FileWriter writer = new FileWriter(path)) {
+            Log.i(DpmTestBase.TAG, "Writing to " + path);
+            Log.i(DpmTestBase.TAG, content);
+            writer.write(content);
+        }
+    }
+
+    private static boolean checkAssertRestrictions(Bundle a, Bundle b) {
+        try {
+            assertRestrictions(a, b);
+            return true;
+        } catch (AssertionFailedError e) {
+            return false;
+        }
+    }
+
+    public void testAssertRestrictions() {
+        final Bundle a = newRestrictions();
+        final Bundle b = newRestrictions("a");
+        final Bundle c = newRestrictions("a");
+        final Bundle d = newRestrictions("b", "c");
+        final Bundle e = newRestrictions("b", "c");
+
+        assertTrue(checkAssertRestrictions(null, null));
+        assertFalse(checkAssertRestrictions(null, a));
+        assertFalse(checkAssertRestrictions(a, null));
+        assertTrue(checkAssertRestrictions(a, a));
+
+        assertFalse(checkAssertRestrictions(a, b));
+        assertTrue(checkAssertRestrictions(b, c));
+
+        assertFalse(checkAssertRestrictions(c, d));
+        assertTrue(checkAssertRestrictions(d, e));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
index 79845d2..4e11762 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -47,31 +47,6 @@
  (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
  */
 public class OwnersTest extends DpmTestBase {
-    private String readAsset(String assetPath) throws IOException {
-        final StringBuilder sb = new StringBuilder();
-        try (BufferedReader br = new BufferedReader(
-                new InputStreamReader(
-                        mRealTestContext.getResources().getAssets().open(assetPath)))) {
-            String line;
-            while ((line = br.readLine()) != null) {
-                sb.append(line);
-                sb.append(System.lineSeparator());
-            }
-        }
-        return sb.toString();
-    }
-
-    private void createLegacyFile(File path, String content)
-            throws IOException {
-        path.getParentFile().mkdirs();
-
-        try (FileWriter writer = new FileWriter(path)) {
-            Log.i(TAG, "Writing to " + path);
-            Log.i(TAG, content);
-            writer.write(content);
-        }
-    }
-
     public void testUpgrade01() throws Exception {
         getContext().addUsers(10, 11, 20, 21);
 
@@ -79,8 +54,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test01/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml"));
 
             owners.load();
 
@@ -99,6 +74,12 @@
             assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -110,6 +91,12 @@
             assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
     }
 
@@ -120,8 +107,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test02/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml"));
 
             owners.load();
 
@@ -142,6 +129,12 @@
 
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -156,6 +149,12 @@
 
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
     }
 
@@ -166,8 +165,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test03/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml"));
 
             owners.load();
 
@@ -196,6 +195,12 @@
                     owners.getProfileOwnerComponent(11));
             assertEquals("1", owners.getProfileOwnerName(11));
             assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -218,9 +223,19 @@
                     owners.getProfileOwnerComponent(11));
             assertEquals("1", owners.getProfileOwnerName(11));
             assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
     }
 
+    /**
+     * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()}
+     * and {@link  Owners#setProfileOwnerUserRestrictionsMigrated(int)}.
+     */
     public void testUpgrade04() throws Exception {
         getContext().addUsers(10, 11, 20, 21);
 
@@ -228,8 +243,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test04/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
 
             owners.load();
 
@@ -262,6 +277,12 @@
                     owners.getProfileOwnerComponent(11));
             assertEquals("1", owners.getProfileOwnerName(11));
             assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+
+            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -288,6 +309,40 @@
                     owners.getProfileOwnerComponent(11));
             assertEquals("1", owners.getProfileOwnerName(11));
             assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+
+            assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
+
+            owners.setDeviceOwnerUserRestrictionsMigrated();
+        }
+
+        {
+            final OwnersTestable owners = new OwnersTestable(getContext());
+            owners.load();
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
+
+            owners.setProfileOwnerUserRestrictionsMigrated(11);
+        }
+
+        {
+            final OwnersTestable owners = new OwnersTestable(getContext());
+            owners.load();
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
+
+            owners.setProfileOwnerUserRestrictionsMigrated(11);
         }
     }
 
@@ -298,8 +353,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test05/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml"));
 
             owners.load();
 
@@ -319,6 +374,12 @@
 
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -332,6 +393,12 @@
 
             assertNull(owners.getSystemUpdatePolicy());
             assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
     }
 
@@ -342,8 +409,8 @@
         {
             final OwnersTestable owners = new OwnersTestable(getContext());
 
-            createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                    readAsset("OwnersTest/test06/input.xml"));
+            DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                    DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml"));
 
             owners.load();
 
@@ -362,6 +429,12 @@
 
             assertNotNull(owners.getSystemUpdatePolicy());
             assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
 
         // Then re-read and check.
@@ -375,6 +448,12 @@
 
             assertNotNull(owners.getSystemUpdatePolicy());
             assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+
+            assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
+            assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
         }
     }
 
@@ -384,8 +463,8 @@
         final OwnersTestable owners = new OwnersTestable(getContext());
 
         // First, migrate to create new-style config files.
-        createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
-                readAsset("OwnersTest/test04/input.xml"));
+        DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
+                DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
 
         owners.load();
 
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 86f5ed7..66c7dbb 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -211,11 +211,14 @@
 
     public void testRestrictions() {
         UserInfo testUser = createUser("User 1", 0);
-        Bundle restrictions = new Bundle();
-        restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
-        restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
-        mUserManager.setUserRestrictions(restrictions, new UserHandle(testUser.id));
+
+        mUserManager.setUserRestriction(
+                UserManager.DISALLOW_INSTALL_APPS, true, new UserHandle(testUser.id));
+        mUserManager.setUserRestriction(
+                UserManager.DISALLOW_CONFIG_WIFI, false, new UserHandle(testUser.id));
+
         Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
+        // Note this will fail if DO already sets those restrictions.
         assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
         assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
         assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index 31763e7..129e537 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -212,6 +212,10 @@
     }
 
     private AlsaDevice waitForAlsaDevice(int card, int device, int type) {
+        if (DEBUG) {
+            Slog.e(TAG, "waitForAlsaDevice(c:" + card + " d:" + device + ")");
+        }
+
         AlsaDevice testDevice = new AlsaDevice(type, card, device);
 
         // This value was empirically determined.
@@ -292,7 +296,8 @@
      */
     /* package */ UsbAudioDevice selectAudioCard(int card) {
         if (DEBUG) {
-            Slog.d(TAG, "selectAudioCard() card:" + card);
+            Slog.d(TAG, "selectAudioCard() card:" + card
+                    + " isCardUsb(): " + mCardsParser.isCardUsb(card));
         }
         if (!mCardsParser.isCardUsb(card)) {
             // Don't. AudioPolicyManager has logic for falling back to internal devices.
@@ -304,6 +309,10 @@
 
         boolean hasPlayback = mDevicesParser.hasPlaybackDevices(card);
         boolean hasCapture = mDevicesParser.hasCaptureDevices(card);
+        if (DEBUG) {
+            Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
+        }
+
         int deviceClass =
             (mCardsParser.isCardUsb(card)
                 ? UsbAudioDevice.kAudioDeviceClass_External
@@ -320,10 +329,6 @@
             return null;
         }
 
-        if (DEBUG) {
-            Slog.d(TAG, "usb: hasPlayback:" + hasPlayback + " hasCapture:" + hasCapture);
-        }
-
         UsbAudioDevice audioDevice =
                 new UsbAudioDevice(card, device, hasPlayback, hasCapture, deviceClass);
         AlsaCardsParser.AlsaCardRecord cardRecord = mCardsParser.getCardRecordFor(card);
@@ -339,14 +344,13 @@
         if (DEBUG) {
             Slog.d(TAG, "UsbAudioManager.selectDefaultDevice()");
         }
-        mCardsParser.scan();
         return selectAudioCard(mCardsParser.getDefaultCard());
     }
 
     /* package */ void usbDeviceAdded(UsbDevice usbDevice) {
        if (DEBUG) {
           Slog.d(TAG, "deviceAdded(): " + usbDevice.getManufacturerName() +
-                  "nm:" + usbDevice.getProductName());
+                  " nm:" + usbDevice.getProductName());
         }
 
         // Is there an audio interface in there?
@@ -361,27 +365,22 @@
                 isAudioDevice = true;
             }
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "  isAudioDevice: " + isAudioDevice);
+        }
         if (!isAudioDevice) {
             return;
         }
 
-        ArrayList<AlsaCardsParser.AlsaCardRecord> prevScanRecs = mCardsParser.getScanRecords();
-        mCardsParser.scan();
-
-        int addedCard = -1;
-        ArrayList<AlsaCardsParser.AlsaCardRecord>
-            newScanRecs = mCardsParser.getNewCardRecords(prevScanRecs);
-        if (newScanRecs.size() > 0) {
-            // This is where we select the just connected device
-            // NOTE - to switch to prefering the first-connected device, just always
-            // take the else clause below.
-            addedCard = newScanRecs.get(0).mCardNum;
-        } else {
-            addedCard = mCardsParser.getDefaultUsbCard();
-        }
+        int addedCard = mCardsParser.getDefaultUsbCard();
 
         // If the default isn't a USB device, let the existing "select internal mechanism"
         // handle the selection.
+        if (DEBUG) {
+            Slog.d(TAG, "  mCardsParser.isCardUsb(" + addedCard + ") = "
+                        + mCardsParser.isCardUsb(addedCard));
+        }
         if (mCardsParser.isCardUsb(addedCard)) {
             UsbAudioDevice audioDevice = selectAudioCard(addedCard);
             if (audioDevice != null) {
@@ -429,6 +428,10 @@
                 }
             }
         }
+
+        if (DEBUG) {
+            Slog.d(TAG, "deviceAdded() - done");
+        }
     }
 
     /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
@@ -439,7 +442,7 @@
 
         UsbAudioDevice audioDevice = mAudioDevices.remove(usbDevice);
         if (audioDevice != null) {
-            if (audioDevice.mHasPlayback || audioDevice.mHasPlayback) {
+            if (audioDevice.mHasPlayback || audioDevice.mHasCapture) {
                 notifyDeviceState(audioDevice, false);
 
                 // if there any external devices left, select one of them
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 3160e39..e0f95cf 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -756,6 +756,8 @@
                         if (mUsbDataUnlocked && active && mCurrentUser != UserHandle.USER_NULL) {
                             Slog.v(TAG, "Current user switched to " + mCurrentUser
                                     + "; resetting USB host stack for MTP or PTP");
+                            // avoid leaking sensitive data from previous user
+                            mUsbDataUnlocked = false;
                             setEnabledFunctions(mCurrentFunctions, true);
                         }
                         mCurrentUser = msg.arg1;
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index f263b4d..861a379 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -178,6 +178,7 @@
      *  Codec: Codec info.
      *  DisplayText: Display text for the call.
      *  AdditionalCallInfo: Additional call info.
+     *  CallRadioTech: The radio tech on which the call is placed.
      */
     public static final String EXTRA_OI = "oi";
     public static final String EXTRA_CNA = "cna";
@@ -187,6 +188,7 @@
     public static final String EXTRA_CODEC = "Codec";
     public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
     public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+    public static final String EXTRA_CALL_RAT_TYPE = "CallRadioTech";
 
     public int mServiceType;
     public int mCallType;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index f563839..d2e4de3 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -144,28 +144,6 @@
             = "android.intent.action.ANY_DATA_STATE";
 
     /**
-     * Broadcast Action: Occurs when a data connection connects to a provisioning apn
-     * and is broadcast by the low level data connection code.
-     * The intent will have the following extra values:</p>
-     * <dl>
-     *   <dt>apn</dt><dd>A string that is the APN associated with this connection.</dd>
-     *   <dt>apnType</dt><dd>A string array of APN types associated with this connection.
-     *      The APN type {@code *} is a special type that means this APN services all types.</dd>
-     *   <dt>linkProperties</dt><dd>{@code LinkProperties} for this APN.</dd>
-     *   <dt>linkCapabilities</dt><dd>The {@code LinkCapabilities} for this APN.</dd>
-     *   <dt>iface</dt><dd>A string that is the name of the interface.</dd>
-     * </dl>
-     *
-     * <p class="note">
-     * Requires the READ_PHONE_STATE permission.
-     *
-     * <p class="note">This is a protected intent that can only be sent
-     * by the system.
-     */
-    public static final String ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN
-            = "android.intent.action.DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN";
-
-    /**
      * Broadcast Action: An attempt to establish a data connection has failed.
      * The intent will have the following extra values:</p>
      * <dl>
diff --git a/tools/aapt2/JavaClassGenerator_test.cpp b/tools/aapt2/JavaClassGenerator_test.cpp
index becf99b..cc5e981 100644
--- a/tools/aapt2/JavaClassGenerator_test.cpp
+++ b/tools/aapt2/JavaClassGenerator_test.cpp
@@ -105,11 +105,9 @@
             .addSimple(u"@android:id/one", ResourceId(0x01020000))
             .addSimple(u"@android:id/two", ResourceId(0x01020001))
             .addSimple(u"@android:id/three", ResourceId(0x01020002))
+            .setSymbolState(u"@android:id/one", ResourceId(0x01020000), SymbolState::kPublic)
+            .setSymbolState(u"@android:id/two", ResourceId(0x01020001), SymbolState::kPrivate)
             .build();
-    ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/one"), {}, {},
-                                      SymbolState::kPublic, &diag));
-    ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:id/two"), {}, {},
-                                      SymbolState::kPrivate, &diag));
 
     JavaClassGeneratorOptions options;
     options.types = JavaClassGeneratorOptions::SymbolTypes::kPublic;
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index bfef9d0..44710eb 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -186,6 +186,7 @@
     Source source;
     ResourceId id;
     SymbolState symbolState = SymbolState::kUndefined;
+    std::u16string comment;
     std::unique_ptr<Value> value;
     std::list<ParsedResource> childResources;
 };
@@ -194,7 +195,11 @@
 static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config,
                                 IDiagnostics* diag, ParsedResource* res) {
     if (res->symbolState != SymbolState::kUndefined) {
-        if (!table->setSymbolState(res->name, res->id, res->source, res->symbolState, diag)) {
+        Symbol symbol;
+        symbol.state = res->symbolState;
+        symbol.source = res->source;
+        symbol.comment = res->comment;
+        if (!table->setSymbolState(res->name, res->id, symbol, diag)) {
             return false;
         }
     }
@@ -203,7 +208,11 @@
         return true;
     }
 
-    if (!table->addResource(res->name, res->id, config, res->source, std::move(res->value), diag)) {
+    // Attach the comment, source and config to the value.
+    res->value->setComment(std::move(res->comment));
+    res->value->setSource(std::move(res->source));
+
+    if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) {
         return false;
     }
 
@@ -275,6 +284,7 @@
         ParsedResource parsedResource;
         parsedResource.name.entry = maybeName.value().toString();
         parsedResource.source = mSource.withLine(parser->getLineNumber());
+        parsedResource.comment = std::move(comment);
 
         bool result = true;
         if (elementName == u"id") {
@@ -368,8 +378,8 @@
  * an Item. If allowRawValue is false, nullptr is returned in this
  * case.
  */
-std::unique_ptr<Item> ResourceParser::parseXml(XmlPullParser* parser, uint32_t typeMask,
-                                               bool allowRawValue) {
+std::unique_ptr<Item> ResourceParser::parseXml(XmlPullParser* parser, const uint32_t typeMask,
+                                               const bool allowRawValue) {
     const size_t beginXmlLine = parser->getLineNumber();
 
     std::u16string rawValue;
@@ -386,8 +396,9 @@
 
     auto onCreateReference = [&](const ResourceName& name) {
         // name.package can be empty here, as it will assume the package name of the table.
-        mTable->addResource(name, {}, mSource.withLine(beginXmlLine), util::make_unique<Id>(),
-                            mDiag);
+        std::unique_ptr<Id> id = util::make_unique<Id>();
+        id->setSource(mSource.withLine(beginXmlLine));
+        mTable->addResource(name, {}, std::move(id), mDiag);
     };
 
     // Process the raw value.
@@ -411,11 +422,12 @@
                 mTable->stringPool.makeRef(styleString.str, StringPool::Context{ 1, mConfig }));
     }
 
-    // We can't parse this so return a RawString if we are allowed.
     if (allowRawValue) {
+        // We can't parse this so return a RawString if we are allowed.
         return util::make_unique<RawString>(
                 mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig }));
     }
+
     return {};
 }
 
@@ -683,8 +695,8 @@
     }
 
     return Attribute::Symbol{
-        Reference(ResourceName{ {}, ResourceType::kId, maybeName.value().toString() }),
-                val.data };
+            Reference(ResourceName({}, ResourceType::kId, maybeName.value().toString())),
+            val.data };
 }
 
 static Maybe<ResourceName> parseXmlAttributeName(StringPiece16 str) {
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 34c68d7..2d5a29d 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -65,12 +65,13 @@
                            StyleString* outStyleString);
 
     /*
-     * Parses the XML subtree and converts it to an Item. The type of Item that can be
-     * parsed is denoted by the `typeMask`. If `allowRawValue` is true and the subtree
-     * can not be parsed as a regular Item, then a RawString is returned. Otherwise
-     * this returns nullptr.
+     * Parses the XML subtree and returns an Item.
+     * The type of Item that can be parsed is denoted by the `typeMask`.
+     * If `allowRawValue` is true and the subtree can not be parsed as a regular Item, then a
+     * RawString is returned. Otherwise this returns false;
      */
-    std::unique_ptr<Item> parseXml(XmlPullParser* parser, uint32_t typeMask, bool allowRawValue);
+    std::unique_ptr<Item> parseXml(XmlPullParser* parser, const uint32_t typeMask,
+                                   const bool allowRawValue);
 
     bool parseResources(XmlPullParser* parser);
     bool parseString(XmlPullParser* parser, ParsedResource* outResource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index a7e9d39..af6bf67 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -379,18 +379,39 @@
 }
 
 TEST_F(ResourceParserTest, ParseCommentsWithResource) {
-    std::string input = "<!-- This is a comment -->\n"
+    std::string input = "<!--This is a comment-->\n"
                         "<string name=\"foo\">Hi</string>";
     ASSERT_TRUE(testParse(input));
 
-    Maybe<ResourceTable::SearchResult> result = mTable.findResource(
-            test::parseNameOrDie(u"@string/foo"));
-    AAPT_ASSERT_TRUE(result);
+    String* value = test::getValue<String>(&mTable, u"@string/foo");
+    ASSERT_NE(nullptr, value);
+    EXPECT_EQ(value->getComment(), u"This is a comment");
+}
 
-    ResourceEntry* entry = result.value().entry;
-    ASSERT_NE(entry, nullptr);
-    ASSERT_FALSE(entry->values.empty());
-    EXPECT_EQ(entry->values.front().comment, u"This is a comment");
+TEST_F(ResourceParserTest, DoNotCombineMultipleComments) {
+    std::string input = "<!--One-->\n"
+                        "<!--Two-->\n"
+                        "<string name=\"foo\">Hi</string>";
+
+    ASSERT_TRUE(testParse(input));
+
+    String* value = test::getValue<String>(&mTable, u"@string/foo");
+    ASSERT_NE(nullptr, value);
+    EXPECT_EQ(value->getComment(), u"Two");
+}
+
+TEST_F(ResourceParserTest, IgnoreCommentBeforeEndTag) {
+    std::string input = "<!--One-->\n"
+                        "<string name=\"foo\">\n"
+                        "  Hi\n"
+                        "<!--Two-->\n"
+                        "</string>";
+
+    ASSERT_TRUE(testParse(input));
+
+    String* value = test::getValue<String>(&mTable, u"@string/foo");
+    ASSERT_NE(nullptr, value);
+    EXPECT_EQ(value->getComment(), u"One");
 }
 
 /*
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index 84674e8..fa4b109 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -19,6 +19,8 @@
 #include "ResourceTable.h"
 #include "ResourceValues.h"
 #include "ValueVisitor.h"
+
+#include "util/Comparators.h"
 #include "util/Util.h"
 
 #include <algorithm>
@@ -29,10 +31,6 @@
 
 namespace aapt {
 
-static bool compareConfigs(const ResourceConfigValue& lhs, const ConfigDescription& rhs) {
-    return lhs.config < rhs;
-}
-
 static bool lessThanType(const std::unique_ptr<ResourceTableType>& lhs, ResourceType rhs) {
     return lhs->type < rhs;
 }
@@ -191,52 +189,50 @@
 static constexpr const char16_t* kValidNameMangledChars = u"._-$";
 
 bool ResourceTable::addResource(const ResourceNameRef& name, const ConfigDescription& config,
-                                const Source& source, std::unique_ptr<Value> value,
-                                IDiagnostics* diag) {
-    return addResourceImpl(name, ResourceId{}, config, source, std::move(value), kValidNameChars,
-                           diag);
+                                std::unique_ptr<Value> value, IDiagnostics* diag) {
+    return addResourceImpl(name, {}, config, std::move(value), kValidNameChars, diag);
 }
 
 bool ResourceTable::addResource(const ResourceNameRef& name, const ResourceId resId,
-                                const ConfigDescription& config, const Source& source,
-                                std::unique_ptr<Value> value, IDiagnostics* diag) {
-    return addResourceImpl(name, resId, config, source, std::move(value), kValidNameChars, diag);
+                                const ConfigDescription& config, std::unique_ptr<Value> value,
+                                IDiagnostics* diag) {
+    return addResourceImpl(name, resId, config, std::move(value), kValidNameChars, diag);
 }
 
 bool ResourceTable::addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
                                      const Source& source, const StringPiece16& path,
                                      IDiagnostics* diag) {
-    return addResourceImpl(name, ResourceId{}, config, source,
-                           util::make_unique<FileReference>(stringPool.makeRef(path)),
-                           kValidNameChars, diag);
+    std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
+            stringPool.makeRef(path));
+    fileRef->setSource(source);
+    return addResourceImpl(name, ResourceId{}, config, std::move(fileRef), kValidNameChars, diag);
 }
 
 bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
                                             const ConfigDescription& config,
-                                            const Source& source,
                                             std::unique_ptr<Value> value,
                                             IDiagnostics* diag) {
-    return addResourceImpl(name, ResourceId{}, config, source, std::move(value),
-                           kValidNameMangledChars, diag);
+    return addResourceImpl(name, ResourceId{}, config, std::move(value), kValidNameMangledChars,
+                           diag);
 }
 
 bool ResourceTable::addResourceAllowMangled(const ResourceNameRef& name,
                                             const ResourceId id,
                                             const ConfigDescription& config,
-                                            const Source& source,
                                             std::unique_ptr<Value> value,
                                             IDiagnostics* diag) {
-    return addResourceImpl(name, id, config, source, std::move(value),
-                           kValidNameMangledChars, diag);
+    return addResourceImpl(name, id, config, std::move(value), kValidNameMangledChars, diag);
 }
 
 bool ResourceTable::addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
-                                    const ConfigDescription& config, const Source& source,
-                                    std::unique_ptr<Value> value, const char16_t* validChars,
-                                    IDiagnostics* diag) {
+                                    const ConfigDescription& config, std::unique_ptr<Value> value,
+                                    const char16_t* validChars, IDiagnostics* diag) {
+    assert(value && "value can't be nullptr");
+    assert(diag && "diagnostics can't be nullptr");
+
     auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
     if (badCharIter != name.entry.end()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(value->getSource())
                     << "resource '"
                     << name
                     << "' has invalid entry name '"
@@ -249,7 +245,7 @@
 
     ResourceTablePackage* package = findOrCreatePackage(name.package);
     if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(value->getSource())
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -263,7 +259,7 @@
 
     ResourceTableType* type = package->findOrCreateType(name.type);
     if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(value->getSource())
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -277,7 +273,7 @@
 
     ResourceEntry* entry = type->findOrCreateEntry(name.entry);
     if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(value->getSource())
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -288,20 +284,20 @@
     }
 
     const auto endIter = entry->values.end();
-    auto iter = std::lower_bound(entry->values.begin(), endIter, config, compareConfigs);
+    auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThan);
     if (iter == endIter || iter->config != config) {
         // This resource did not exist before, add it.
-        entry->values.insert(iter, ResourceConfigValue{ config, source, {}, std::move(value) });
+        entry->values.insert(iter, ResourceConfigValue{ config, std::move(value) });
     } else {
         int collisionResult = resolveValueCollision(iter->value.get(), value.get());
         if (collisionResult > 0) {
             // Take the incoming value.
-            *iter = ResourceConfigValue{ config, source, {}, std::move(value) };
+            iter->value = std::move(value);
         } else if (collisionResult == 0) {
-            diag->error(DiagMessage(source)
+            diag->error(DiagMessage(value->getSource())
                         << "duplicate value for resource '" << name << "' "
-                        << "with config '" << iter->config << "'");
-            diag->error(DiagMessage(iter->source)
+                        << "with config '" << config << "'");
+            diag->error(DiagMessage(iter->value->getSource())
                         << "resource previously defined here");
             return false;
         }
@@ -316,27 +312,29 @@
 }
 
 bool ResourceTable::setSymbolState(const ResourceNameRef& name, const ResourceId resId,
-                                   const Source& source, SymbolState state, IDiagnostics* diag) {
-    return setSymbolStateImpl(name, resId, source, state, kValidNameChars, diag);
+                                   const Symbol& symbol, IDiagnostics* diag) {
+    return setSymbolStateImpl(name, resId, symbol, kValidNameChars, diag);
 }
 
-bool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId,
-                                               const Source& source, SymbolState state,
-                                               IDiagnostics* diag) {
-    return setSymbolStateImpl(name, resId, source, state, kValidNameMangledChars, diag);
+bool ResourceTable::setSymbolStateAllowMangled(const ResourceNameRef& name,
+                                               const ResourceId resId,
+                                               const Symbol& symbol, IDiagnostics* diag) {
+    return setSymbolStateImpl(name, resId, symbol, kValidNameMangledChars, diag);
 }
 
 bool ResourceTable::setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
-                                       const Source& source, SymbolState state,
-                                       const char16_t* validChars, IDiagnostics* diag) {
-    if (state == SymbolState::kUndefined) {
+                                       const Symbol& symbol, const char16_t* validChars,
+                                       IDiagnostics* diag) {
+    assert(diag && "diagnostics can't be nullptr");
+
+    if (symbol.state == SymbolState::kUndefined) {
         // Nothing to do.
         return true;
     }
 
     auto badCharIter = util::findNonAlphaNumericAndNotInSet(name.entry, validChars);
     if (badCharIter != name.entry.end()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(symbol.source)
                     << "resource '"
                     << name
                     << "' has invalid entry name '"
@@ -349,7 +347,7 @@
 
     ResourceTablePackage* package = findOrCreatePackage(name.package);
     if (resId.isValid() && package->id && package->id.value() != resId.packageId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(symbol.source)
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -363,7 +361,7 @@
 
     ResourceTableType* type = package->findOrCreateType(name.type);
     if (resId.isValid() && type->id && type->id.value() != resId.typeId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(symbol.source)
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -377,7 +375,7 @@
 
     ResourceEntry* entry = type->findOrCreateEntry(name.entry);
     if (resId.isValid() && entry->id && entry->id.value() != resId.entryId()) {
-        diag->error(DiagMessage(source)
+        diag->error(DiagMessage(symbol.source)
                     << "trying to add resource '"
                     << name
                     << "' with ID "
@@ -388,15 +386,14 @@
     }
 
     // Only mark the type state as public, it doesn't care about being private.
-    if (state == SymbolState::kPublic) {
+    if (symbol.state == SymbolState::kPublic) {
         type->symbolStatus.state = SymbolState::kPublic;
     }
 
     // Downgrading to a private symbol from a public one is not allowed.
     if (entry->symbolStatus.state != SymbolState::kPublic) {
-        if (entry->symbolStatus.state != state) {
-            entry->symbolStatus.state = state;
-            entry->symbolStatus.source = source;
+        if (entry->symbolStatus.state != symbol.state) {
+            entry->symbolStatus = std::move(symbol);
         }
     }
 
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index be90936..980504b 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -47,12 +47,10 @@
 };
 
 /**
- * The resource value for a specific configuration.
+ * Represents a value defined for a given configuration.
  */
 struct ResourceConfigValue {
     ConfigDescription config;
-    Source source;
-    std::u16string comment;
     std::unique_ptr<Value> value;
 };
 
@@ -158,12 +156,11 @@
     static int resolveValueCollision(Value* existing, Value* incoming);
 
     bool addResource(const ResourceNameRef& name, const ConfigDescription& config,
-                     const Source& source, std::unique_ptr<Value> value,
-                     IDiagnostics* diag);
+                     std::unique_ptr<Value> value, IDiagnostics* diag);
 
     bool addResource(const ResourceNameRef& name, const ResourceId resId,
-                     const ConfigDescription& config, const Source& source,
-                     std::unique_ptr<Value> value, IDiagnostics* diag);
+                     const ConfigDescription& config, std::unique_ptr<Value> value,
+                     IDiagnostics* diag);
 
     bool addFileReference(const ResourceNameRef& name, const ConfigDescription& config,
                           const Source& source, const StringPiece16& path, IDiagnostics* diag);
@@ -174,18 +171,18 @@
      * names.
      */
     bool addResourceAllowMangled(const ResourceNameRef& name, const ConfigDescription& config,
-                                 const Source& source, std::unique_ptr<Value> value,
-                                 IDiagnostics* diag);
+                                 std::unique_ptr<Value> value, IDiagnostics* diag);
 
     bool addResourceAllowMangled(const ResourceNameRef& name, const ResourceId id,
-                                 const ConfigDescription& config,
-                                 const Source& source, std::unique_ptr<Value> value,
+                                 const ConfigDescription& config, std::unique_ptr<Value> value,
                                  IDiagnostics* diag);
 
-    bool setSymbolState(const ResourceNameRef& name, const ResourceId resId, const Source& source,
-                        SymbolState state, IDiagnostics* diag);
+    bool setSymbolState(const ResourceNameRef& name, const ResourceId resId,
+                        const Symbol& symbol, IDiagnostics* diag);
+
     bool setSymbolStateAllowMangled(const ResourceNameRef& name, const ResourceId resId,
-                                    const Source& source, SymbolState state, IDiagnostics* diag);
+                                    const Symbol& symbol, IDiagnostics* diag);
+
     struct SearchResult {
         ResourceTablePackage* package;
         ResourceTableType* type;
@@ -224,13 +221,11 @@
 private:
     ResourceTablePackage* findOrCreatePackage(const StringPiece16& name);
 
-    bool addResourceImpl(const ResourceNameRef& name, const ResourceId resId,
-                         const ConfigDescription& config, const Source& source,
-                         std::unique_ptr<Value> value, const char16_t* validChars,
-                         IDiagnostics* diag);
-    bool setSymbolStateImpl(const ResourceNameRef& name, const ResourceId resId,
-                            const Source& source, SymbolState state, const char16_t* validChars,
-                            IDiagnostics* diag);
+    bool addResourceImpl(const ResourceNameRef& name, ResourceId resId,
+                         const ConfigDescription& config, std::unique_ptr<Value> value,
+                         const char16_t* validChars, IDiagnostics* diag);
+    bool setSymbolStateImpl(const ResourceNameRef& name, ResourceId resId,
+                            const Symbol& symbol, const char16_t* validChars, IDiagnostics* diag);
 };
 
 } // namespace aapt
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 2055a80..42508fe 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -19,7 +19,7 @@
 #include "ResourceValues.h"
 #include "util/Util.h"
 
-#include "test/Common.h"
+#include "test/Builders.h"
 
 #include <algorithm>
 #include <gtest/gtest.h>
@@ -42,22 +42,26 @@
     ResourceTable table;
 
     EXPECT_FALSE(table.addResource(
-            ResourceNameRef{ u"android", ResourceType::kId, u"hey,there" },
-            {}, Source{ "test.xml", 21 },
-            util::make_unique<Id>(), &mDiagnostics));
+            ResourceNameRef(u"android", ResourceType::kId, u"hey,there"),
+            ConfigDescription{},
+            test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
+            &mDiagnostics));
 
     EXPECT_FALSE(table.addResource(
-            ResourceNameRef{ u"android", ResourceType::kId, u"hey:there" },
-            {}, Source{ "test.xml", 21 },
-            util::make_unique<Id>(), &mDiagnostics));
+            ResourceNameRef(u"android", ResourceType::kId, u"hey:there"),
+            ConfigDescription{},
+            test::ValueBuilder<Id>().setSource("test.xml", 21u).build(),
+            &mDiagnostics));
 }
 
 TEST_F(ResourceTableTest, AddOneResource) {
     ResourceTable table;
 
-    EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"), {},
-                                  Source{ "test/path/file.xml", 23 },
-                                  util::make_unique<Id>(), &mDiagnostics));
+    EXPECT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/id"),
+                                  ConfigDescription{},
+                                  test::ValueBuilder<Id>()
+                                          .setSource("test/path/file.xml", 23u).build(),
+                                  &mDiagnostics));
 
     ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
 }
@@ -71,23 +75,29 @@
 
     EXPECT_TRUE(table.addResource(
             test::parseNameOrDie(u"@android:attr/layout_width"),
-            config, Source{ "test/path/file.xml", 10 },
-            util::make_unique<Id>(), &mDiagnostics));
+            config,
+            test::ValueBuilder<Id>().setSource("test/path/file.xml", 10u).build(),
+            &mDiagnostics));
 
     EXPECT_TRUE(table.addResource(
             test::parseNameOrDie(u"@android:attr/id"),
-            config, Source{ "test/path/file.xml", 12 },
-            util::make_unique<Id>(), &mDiagnostics));
+            config,
+            test::ValueBuilder<Id>().setSource("test/path/file.xml", 12u).build(),
+            &mDiagnostics));
 
     EXPECT_TRUE(table.addResource(
             test::parseNameOrDie(u"@android:string/ok"),
-            config, Source{ "test/path/file.xml", 14 },
-            util::make_unique<Id>(), &mDiagnostics));
+            config,
+            test::ValueBuilder<Id>().setSource("test/path/file.xml", 14u).build(),
+            &mDiagnostics));
 
     EXPECT_TRUE(table.addResource(
             test::parseNameOrDie(u"@android:string/ok"),
-            languageConfig, Source{ "test/path/file.xml", 20 },
-            util::make_unique<BinaryPrimitive>(android::Res_value{}), &mDiagnostics));
+            languageConfig,
+            test::ValueBuilder<BinaryPrimitive>(android::Res_value{})
+                    .setSource("test/path/file.xml", 20u)
+                    .build(),
+            &mDiagnostics));
 
     ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/layout_width"));
     ASSERT_NE(nullptr, test::getValue<Id>(&table, u"@android:attr/id"));
@@ -99,14 +109,14 @@
 TEST_F(ResourceTableTest, OverrideWeakResourceValue) {
     ResourceTable table;
 
-    ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), {}, {},
+    ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
                                   util::make_unique<Attribute>(true), &mDiagnostics));
 
     Attribute* attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
     ASSERT_NE(nullptr, attr);
     EXPECT_TRUE(attr->isWeak());
 
-    ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), {}, {},
+    ASSERT_TRUE(table.addResource(test::parseNameOrDie(u"@android:attr/foo"), ConfigDescription{},
                                   util::make_unique<Attribute>(false), &mDiagnostics));
 
     attr = test::getValue<Attribute>(&table, u"@android:attr/foo");
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index ecc5cd2..f312d75 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -15,11 +15,12 @@
  */
 
 #include "Resource.h"
-#include "flatten/ResourceTypeExtensions.h"
 #include "ResourceValues.h"
-#include "util/Util.h"
 #include "ValueVisitor.h"
 
+#include "util/Util.h"
+#include "flatten/ResourceTypeExtensions.h"
+
 #include <androidfw/ResourceTypes.h>
 #include <limits>
 
@@ -35,18 +36,10 @@
     visitor->visit(static_cast<Derived*>(this));
 }
 
-bool Value::isItem() const {
-    return false;
-}
-
 bool Value::isWeak() const {
     return false;
 }
 
-bool Item::isItem() const {
-    return true;
-}
-
 RawString::RawString(const StringPool::Ref& ref) : value(ref) {
 }
 
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index 0dae091..2629153 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -41,17 +41,42 @@
 	virtual ~Value() = default;
 
     /**
-     * Whether or not this is an Item.
-     */
-    virtual bool isItem() const;
-
-    /**
      * Whether this value is weak and can be overridden without
      * warning or error. Default for base class is false.
      */
     virtual bool isWeak() const;
 
     /**
+     * Returns the source where this value was defined.
+     */
+    const Source& getSource() const {
+        return mSource;
+    }
+
+    void setSource(const Source& source) {
+        mSource = source;
+    }
+
+    void setSource(Source&& source) {
+        mSource = std::move(source);
+    }
+
+    /**
+     * Returns the comment that was associated with this resource.
+     */
+    StringPiece16 getComment() const {
+        return mComment;
+    }
+
+    void setComment(const StringPiece16& str) {
+        mComment = str.toString();
+    }
+
+    void setComment(std::u16string&& str) {
+        mComment = std::move(str);
+    }
+
+    /**
      * Calls the appropriate overload of ValueVisitor.
      */
     virtual void accept(RawValueVisitor* visitor) = 0;
@@ -65,6 +90,10 @@
      * Human readable printout of this value.
      */
     virtual void print(std::ostream* out) const = 0;
+
+private:
+    Source mSource;
+    std::u16string mComment;
 };
 
 /**
@@ -80,11 +109,6 @@
  */
 struct Item : public Value {
     /**
-     * An Item is, of course, an Item.
-     */
-    virtual bool isItem() const override;
-
-    /**
      * Clone the Item.
      */
     virtual Item* clone(StringPool* newPool) const override = 0;
diff --git a/tools/aapt2/ValueVisitor.h b/tools/aapt2/ValueVisitor.h
index ee058aa..94042e3 100644
--- a/tools/aapt2/ValueVisitor.h
+++ b/tools/aapt2/ValueVisitor.h
@@ -115,6 +115,18 @@
 };
 
 /**
+ * Specialization that checks if the value is an Item.
+ */
+template <>
+struct DynCastVisitor<Item> : public RawValueVisitor {
+    Item* value = nullptr;
+
+    void visitItem(Item* item) override {
+        value = item;
+    }
+};
+
+/**
  * Returns a valid pointer to T if the Value is of subtype T.
  * Otherwise, returns nullptr.
  */
diff --git a/tools/aapt2/XmlPullParser.cpp b/tools/aapt2/XmlPullParser.cpp
index 1b9499d..cff935c 100644
--- a/tools/aapt2/XmlPullParser.cpp
+++ b/tools/aapt2/XmlPullParser.cpp
@@ -97,7 +97,7 @@
 }
 
 const std::u16string& XmlPullParser::getComment() const {
-    return mEventQueue.front().comment;
+    return mEventQueue.front().data1;
 }
 
 size_t XmlPullParser::getLineNumber() const {
diff --git a/tools/aapt2/XmlPullParser.h b/tools/aapt2/XmlPullParser.h
index f7d7a03..a0ce21d 100644
--- a/tools/aapt2/XmlPullParser.h
+++ b/tools/aapt2/XmlPullParser.h
@@ -158,7 +158,6 @@
         size_t depth;
         std::u16string data1;
         std::u16string data2;
-        std::u16string comment;
         std::vector<Attribute> attributes;
     };
 
diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp
index 095552a..47fa2a6 100644
--- a/tools/aapt2/flatten/TableFlattener.cpp
+++ b/tools/aapt2/flatten/TableFlattener.cpp
@@ -292,7 +292,7 @@
     SymbolWriter* mSymbols;
     StringPool* mSourcePool;
 
-    template <typename T>
+    template <typename T, bool IsItem>
     T* writeEntry(FlatEntry* entry, BigBuffer* buffer) {
         static_assert(std::is_same<ResTable_entry, T>::value ||
                       std::is_same<ResTable_entry_ext, T>::value,
@@ -308,7 +308,7 @@
             outEntry->flags |= ResTable_entry::FLAG_WEAK;
         }
 
-        if (!entry->value->isItem()) {
+        if (!IsItem) {
             outEntry->flags |= ResTable_entry::FLAG_COMPLEX;
         }
 
@@ -329,8 +329,8 @@
     }
 
     bool flattenValue(FlatEntry* entry, BigBuffer* buffer) {
-        if (entry->value->isItem()) {
-            writeEntry<ResTable_entry>(entry, buffer);
+        if (Item* item = valueCast<Item>(entry->value)) {
+            writeEntry<ResTable_entry, true>(entry, buffer);
             if (Reference* ref = valueCast<Reference>(entry->value)) {
                 if (!ref->id) {
                     assert(ref->name && "reference must have at least a name");
@@ -339,12 +339,12 @@
                 }
             }
             Res_value* outValue = buffer->nextBlock<Res_value>();
-            bool result = static_cast<Item*>(entry->value)->flatten(outValue);
+            bool result = item->flatten(outValue);
             assert(result && "flatten failed");
             outValue->size = util::hostToDevice16(sizeof(*outValue));
         } else {
             const size_t beforeEntry = buffer->size();
-            ResTable_entry_ext* outEntry = writeEntry<ResTable_entry_ext>(entry, buffer);
+            ResTable_entry_ext* outEntry = writeEntry<ResTable_entry_ext, false>(entry, buffer);
             MapFlattenVisitor visitor(mSymbols, entry, buffer);
             entry->value->accept(&visitor);
             outEntry->count = util::hostToDevice32(visitor.mEntryCount);
@@ -551,17 +551,27 @@
             // configuration available. Here we reverse this to match the binary table.
             std::map<ConfigDescription, std::vector<FlatEntry>> configToEntryListMap;
             for (ResourceEntry* entry : sortedEntries) {
-                const size_t keyIndex = mKeyPool.makeRef(entry->name).getIndex();
+                const uint32_t keyIndex = (uint32_t) mKeyPool.makeRef(entry->name).getIndex();
 
                 // Group values by configuration.
                 for (auto& configValue : entry->values) {
-                   configToEntryListMap[configValue.config].push_back(FlatEntry{
-                            entry, configValue.value.get(), (uint32_t) keyIndex,
-                            (uint32_t)(mSourcePool->makeRef(util::utf8ToUtf16(
-                                    configValue.source.path)).getIndex()),
-                            (uint32_t)(configValue.source.line
-                                    ? configValue.source.line.value() : 0)
-                   });
+                    Value* value = configValue.value.get();
+
+                    const StringPool::Ref sourceRef = mSourcePool->makeRef(
+                            util::utf8ToUtf16(value->getSource().path));
+
+                    uint32_t lineNumber = 0;
+                    if (value->getSource().line) {
+                        lineNumber = value->getSource().line.value();
+                    }
+
+                    configToEntryListMap[configValue.config]
+                            .push_back(FlatEntry{
+                                    entry,
+                                    value,
+                                    keyIndex,
+                                    (uint32_t) sourceRef.getIndex(),
+                                    lineNumber });
                 }
             }
 
diff --git a/tools/aapt2/link/AutoVersioner.cpp b/tools/aapt2/link/AutoVersioner.cpp
index 0ccafc2..11fcc5d 100644
--- a/tools/aapt2/link/AutoVersioner.cpp
+++ b/tools/aapt2/link/AutoVersioner.cpp
@@ -20,21 +20,18 @@
 #include "ValueVisitor.h"
 
 #include "link/Linkers.h"
+#include "util/Comparators.h"
 
 #include <algorithm>
 #include <cassert>
 
 namespace aapt {
 
-static bool cmpConfigValue(const ResourceConfigValue& lhs, const ConfigDescription& config) {
-    return lhs.config < config;
-}
-
 bool shouldGenerateVersionedResource(const ResourceEntry* entry, const ConfigDescription& config,
                                      const int sdkVersionToGenerate) {
     assert(sdkVersionToGenerate > config.sdkVersion);
     const auto endIter = entry->values.end();
-    auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmpConfigValue);
+    auto iter = std::lower_bound(entry->values.begin(), endIter, config, cmp::lessThan);
 
     // The source config came from this list, so it should be here.
     assert(iter != entry->values.end());
@@ -107,21 +104,16 @@
                             // We found attributes from a higher SDK level. Check that
                             // there is no other defined resource for the version we want to
                             // generate.
-                            if (shouldGenerateVersionedResource(entry.get(), configValue.config,
+                            if (shouldGenerateVersionedResource(entry.get(),
+                                                                configValue.config,
                                                                 minSdkStripped.value())) {
                                 // Let's create a new Style for this versioned resource.
                                 ConfigDescription newConfig(configValue.config);
                                 newConfig.sdkVersion = minSdkStripped.value();
 
-                                ResourceConfigValue newValue = {
-                                        newConfig,
-                                        configValue.source,
-                                        configValue.comment,
-                                        std::unique_ptr<Value>(configValue.value->clone(
-                                                &table->stringPool))
-                                };
-
-                                Style* newStyle = static_cast<Style*>(newValue.value.get());
+                                std::unique_ptr<Style> newStyle(style->clone(&table->stringPool));
+                                newStyle->setComment(style->getComment());
+                                newStyle->setSource(style->getSource());
 
                                 // Move the previously stripped attributes into this style.
                                 newStyle->entries.insert(newStyle->entries.end(),
@@ -130,9 +122,13 @@
 
                                 // Insert the new Resource into the correct place.
                                 auto iter = std::lower_bound(entry->values.begin(),
-                                                             entry->values.end(), newConfig,
-                                                             cmpConfigValue);
-                                entry->values.insert(iter, std::move(newValue));
+                                                             entry->values.end(),
+                                                             newConfig,
+                                                             cmp::lessThan);
+
+                                entry->values.insert(
+                                        iter,
+                                        ResourceConfigValue{ newConfig, std::move(newStyle) });
                             }
                         }
                     }
diff --git a/tools/aapt2/link/Link.cpp b/tools/aapt2/link/Link.cpp
index b84f2e0..ad701de 100644
--- a/tools/aapt2/link/Link.cpp
+++ b/tools/aapt2/link/Link.cpp
@@ -266,13 +266,14 @@
                 for (const auto& type : package->types) {
                     for (const auto& entry : type->entries) {
                         for (const auto& configValue : entry->values) {
-                            mContext.getDiagnostics()->error(DiagMessage(configValue.source)
-                                                             << "defined resource '"
-                                                             << ResourceNameRef(package->name,
-                                                                                type->type,
-                                                                                entry->name)
-                                                             << "' for external package '"
-                                                             << package->name << "'");
+                            mContext.getDiagnostics()->error(
+                                    DiagMessage(configValue.value->getSource())
+                                                << "defined resource '"
+                                                << ResourceNameRef(package->name,
+                                                                   type->type,
+                                                                   entry->name)
+                                                << "' for external package '"
+                                                << package->name << "'");
                             error = true;
                         }
                     }
@@ -472,10 +473,11 @@
 
                         Maybe<ResourceName> mangledName = mContext.getNameMangler()->mangleName(
                                 exportedSymbol.name);
-                        if (!mergedTable.addResource(
+                        std::unique_ptr<Id> id = util::make_unique<Id>();
+                        id->setSource(f.source.withLine(exportedSymbol.line));
+                        if (!mergedTable.addResourceAllowMangled(
                                 mangledName ? mangledName.value() : exportedSymbol.name,
-                                {}, {}, f.source.withLine(exportedSymbol.line),
-                                util::make_unique<Id>(), mContext.getDiagnostics())) {
+                                {}, std::move(id), mContext.getDiagnostics())) {
                             error = true;
                         }
                     }
diff --git a/tools/aapt2/link/PrivateAttributeMover_test.cpp b/tools/aapt2/link/PrivateAttributeMover_test.cpp
index a2f8d19..dbe0c92 100644
--- a/tools/aapt2/link/PrivateAttributeMover_test.cpp
+++ b/tools/aapt2/link/PrivateAttributeMover_test.cpp
@@ -30,13 +30,9 @@
             .addSimple(u"@android:attr/privateA")
             .addSimple(u"@android:attr/publicB")
             .addSimple(u"@android:attr/privateB")
+            .setSymbolState(u"@android:attr/publicA", ResourceId(0x01010000), SymbolState::kPublic)
+            .setSymbolState(u"@android:attr/publicB", ResourceId(0x01010000), SymbolState::kPublic)
             .build();
-    ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:attr/publicA"),
-                                      ResourceId(0x01010000), {}, SymbolState::kPublic,
-                                      context->getDiagnostics()));
-    ASSERT_TRUE(table->setSymbolState(test::parseNameOrDie(u"@android:attr/publicB"),
-                                      ResourceId(0x01010002), {}, SymbolState::kPublic,
-                                      context->getDiagnostics()));
 
     PrivateAttributeMover mover;
     ASSERT_TRUE(mover.consume(context.get(), table.get()));
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index b4fb996..8c924b5 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -206,13 +206,13 @@
 
                 if (!(typeMask & ResourceUtils::androidTypeToAttributeTypeMask(val.dataType))) {
                     // The actual type of this item is incompatible with the attribute.
-                    DiagMessage msg;
+                    DiagMessage msg(style->getSource());
                     buildAttributeMismatchMessage(&msg, s->attribute.get(), entry.value.get());
                     mContext->getDiagnostics()->error(msg);
                     mError = true;
                 }
             } else {
-                DiagMessage msg;
+                DiagMessage msg(style->getSource());
                 msg << "style attribute '";
                 if (entry.key.name) {
                     msg << entry.key.name.value().package << ":" << entry.key.name.value().entry;
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index db52546..636c2ba 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -19,6 +19,7 @@
 #include "ValueVisitor.h"
 
 #include "link/TableMerger.h"
+#include "util/Comparators.h"
 #include "util/Util.h"
 
 #include <cassert>
@@ -120,27 +121,24 @@
             }
 
             for (ResourceConfigValue& srcValue : srcEntry->values) {
-                auto cmp = [](const ResourceConfigValue& a,
-                              const ConfigDescription& b) -> bool {
-                    return a.config < b;
-                };
-
                 auto iter = std::lower_bound(dstEntry->values.begin(), dstEntry->values.end(),
-                                             srcValue.config, cmp);
+                                             srcValue.config, cmp::lessThan);
 
                 if (iter != dstEntry->values.end() && iter->config == srcValue.config) {
                     const int collisionResult = ResourceTable::resolveValueCollision(
                             iter->value.get(), srcValue.value.get());
                     if (collisionResult == 0) {
                         // Error!
-                        ResourceNameRef resourceName =
-                                { srcPackage->name, srcType->type, srcEntry->name };
-                        mContext->getDiagnostics()->error(DiagMessage(srcValue.source)
+                        ResourceNameRef resourceName(srcPackage->name,
+                                                     srcType->type,
+                                                     srcEntry->name);
+
+                        mContext->getDiagnostics()->error(DiagMessage(srcValue.value->getSource())
                                                           << "resource '" << resourceName
                                                           << "' has a conflicting value for "
                                                           << "configuration ("
                                                           << srcValue.config << ")");
-                        mContext->getDiagnostics()->note(DiagMessage(iter->source)
+                        mContext->getDiagnostics()->note(DiagMessage(iter->value->getSource())
                                                          << "originally defined here");
                         error = true;
                         continue;
@@ -150,16 +148,12 @@
                     }
 
                 } else {
-                    // Insert a new value.
-                    iter = dstEntry->values.insert(iter,
-                                                   ResourceConfigValue{ srcValue.config });
+                    // Insert a place holder value. We will fill it in below.
+                    iter = dstEntry->values.insert(iter, ResourceConfigValue{ srcValue.config });
                 }
 
-                iter->source = std::move(srcValue.source);
-                iter->comment = std::move(srcValue.comment);
                 if (manglePackage) {
-                    iter->value = cloneAndMangle(srcTable, srcPackage->name,
-                                                 srcValue.value.get());
+                    iter->value = cloneAndMangle(srcTable, srcPackage->name, srcValue.value.get());
                 } else {
                     iter->value = clone(srcValue.value.get());
                 }
@@ -179,7 +173,11 @@
             std::u16string mangledEntry = NameMangler::mangleEntry(package, entry.toString());
             std::u16string newPath = prefix.toString() + mangledEntry + suffix.toString();
             mFilesToMerge.push(FileToMerge{ table, *f->path, newPath });
-            return util::make_unique<FileReference>(mMasterTable->stringPool.makeRef(newPath));
+            std::unique_ptr<FileReference> fileRef = util::make_unique<FileReference>(
+                    mMasterTable->stringPool.makeRef(newPath));
+            fileRef->setComment(f->getComment());
+            fileRef->setSource(f->getSource());
+            return std::move(fileRef);
         }
     }
     return clone(value);
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index c96b080..7309396 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -16,9 +16,11 @@
 
 #include "ConfigDescription.h"
 #include "Resource.h"
-#include "util/Util.h"
+#include "ValueVisitor.h"
 
 #include "process/SymbolTable.h"
+#include "util/Comparators.h"
+#include "util/Util.h"
 
 #include <androidfw/AssetManager.h>
 #include <androidfw/ResourceTypes.h>
@@ -34,7 +36,7 @@
     if (!result) {
         if (name.type == ResourceType::kAttr) {
             // Recurse and try looking up a private attribute.
-            return findByName(ResourceName{ name.package, ResourceType::kAttrPrivate, name.entry });
+            return findByName(ResourceName(name.package, ResourceType::kAttrPrivate, name.entry));
         }
         return {};
     }
@@ -48,28 +50,26 @@
     }
 
     std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
-    symbol->id = ResourceId{
-            sr.package->id.value(), sr.type->id.value(), sr.entry->id.value() };
+    symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
 
     if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
-        auto lt = [](ResourceConfigValue& lhs, const ConfigDescription& rhs) -> bool {
-            return lhs.config < rhs;
-        };
-
         const ConfigDescription kDefaultConfig;
         auto iter = std::lower_bound(sr.entry->values.begin(), sr.entry->values.end(),
-                                     kDefaultConfig, lt);
+                                     kDefaultConfig, cmp::lessThan);
 
         if (iter != sr.entry->values.end() && iter->config == kDefaultConfig) {
             // This resource has an Attribute.
-            symbol->attribute = util::make_unique<Attribute>(
-                    *static_cast<Attribute*>(iter->value.get()));
+            if (Attribute* attr = valueCast<Attribute>(iter->value.get())) {
+                symbol->attribute = std::unique_ptr<Attribute>(attr->clone(nullptr));
+            } else {
+                return {};
+            }
         }
     }
 
     if (name.type == ResourceType::kAttrPrivate) {
         // Masquerade this entry as kAttr.
-        mCache.put(ResourceName{ name.package, ResourceType::kAttr, name.entry }, symbol);
+        mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
     } else {
         mCache.put(name, symbol);
     }
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 0383c44..1b510e7 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -43,7 +43,7 @@
         return *this;
     }
 
-    ResourceTableBuilder& addSimple(const StringPiece16& name, ResourceId id = {}) {
+    ResourceTableBuilder& addSimple(const StringPiece16& name, const ResourceId id = {}) {
         return addValue(name, id, util::make_unique<Id>());
     }
 
@@ -51,7 +51,7 @@
         return addReference(name, {}, ref);
     }
 
-    ResourceTableBuilder& addReference(const StringPiece16& name, ResourceId id,
+    ResourceTableBuilder& addReference(const StringPiece16& name, const ResourceId id,
                                        const StringPiece16& ref) {
         return addValue(name, id, util::make_unique<Reference>(parseNameOrDie(ref)));
     }
@@ -60,7 +60,7 @@
         return addString(name, {}, str);
     }
 
-    ResourceTableBuilder& addString(const StringPiece16& name, ResourceId id,
+    ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id,
                                     const StringPiece16& str) {
         return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str)));
     }
@@ -69,31 +69,43 @@
         return addFileReference(name, {}, path);
     }
 
-    ResourceTableBuilder& addFileReference(const StringPiece16& name, ResourceId id,
+    ResourceTableBuilder& addFileReference(const StringPiece16& name, const ResourceId id,
                                            const StringPiece16& path) {
         return addValue(name, id,
                         util::make_unique<FileReference>(mTable->stringPool.makeRef(path)));
     }
 
 
-    ResourceTableBuilder& addValue(const StringPiece16& name, std::unique_ptr<Value> value) {
+    ResourceTableBuilder& addValue(const StringPiece16& name,
+                                   std::unique_ptr<Value> value) {
         return addValue(name, {}, std::move(value));
     }
 
-    ResourceTableBuilder& addValue(const StringPiece16& name, ResourceId id,
+    ResourceTableBuilder& addValue(const StringPiece16& name, const ResourceId id,
                                        std::unique_ptr<Value> value) {
         return addValue(name, id, {}, std::move(value));
     }
 
-    ResourceTableBuilder& addValue(const StringPiece16& name, ResourceId id,
-                                   const ConfigDescription& config, std::unique_ptr<Value> value) {
+    ResourceTableBuilder& addValue(const StringPiece16& name, const ResourceId id,
+                                   const ConfigDescription& config,
+                                   std::unique_ptr<Value> value) {
         ResourceName resName = parseNameOrDie(name);
-        bool result = mTable->addResourceAllowMangled(resName, id, config, {}, std::move(value),
+        bool result = mTable->addResourceAllowMangled(resName, id, config, std::move(value),
                                                       &mDiagnostics);
         assert(result);
         return *this;
     }
 
+    ResourceTableBuilder& setSymbolState(const StringPiece16& name, ResourceId id,
+                                         SymbolState state) {
+        ResourceName resName = parseNameOrDie(name);
+        Symbol symbol;
+        symbol.state = state;
+        bool result = mTable->setSymbolStateAllowMangled(resName, id, symbol, &mDiagnostics);
+        assert(result);
+        return *this;
+    }
+
     std::unique_ptr<ResourceTable> build() {
         return std::move(mTable);
     }
@@ -106,6 +118,32 @@
     return reference;
 }
 
+template <typename T>
+class ValueBuilder {
+private:
+    std::unique_ptr<Value> mValue;
+
+public:
+    template <typename... Args>
+    ValueBuilder(Args&&... args) : mValue(new T{ std::forward<Args>(args)... }) {
+    }
+
+    template <typename... Args>
+    ValueBuilder& setSource(Args&&... args) {
+        mValue->setSource(Source{ std::forward<Args>(args)... });
+        return *this;
+    }
+
+    ValueBuilder& setComment(const StringPiece16& str) {
+        mValue->setComment(str);
+        return *this;
+    }
+
+    std::unique_ptr<Value> build() {
+        return std::move(mValue);
+    }
+};
+
 class AttributeBuilder {
 private:
     std::unique_ptr<Attribute> mAttr;
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp
index c7a715e..314c1e8 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.cpp
+++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp
@@ -422,26 +422,24 @@
         const ResourceName name(package->name, *parsedType,
                                 util::getString(mKeyPool, entry->key.index).toString());
 
-        Source source;
+        Symbol symbol;
         if (mSourcePool.getError() == NO_ERROR) {
-            source.path = util::utf16ToUtf8(util::getString(
+            symbol.source.path = util::utf16ToUtf8(util::getString(
                     mSourcePool, util::deviceToHost32(entry->source.index)));
-            source.line = util::deviceToHost32(entry->sourceLine);
+            symbol.source.line = util::deviceToHost32(entry->sourceLine);
         }
 
-        SymbolState state = SymbolState::kUndefined;
         switch (util::deviceToHost16(entry->state)) {
         case Public_entry::kPrivate:
-            state = SymbolState::kPrivate;
+            symbol.state = SymbolState::kPrivate;
             break;
 
         case Public_entry::kPublic:
-            state = SymbolState::kPublic;
+            symbol.state = SymbolState::kPublic;
             break;
         }
 
-        if (!mTable->setSymbolStateAllowMangled(name, resId, source, state,
-                                                mContext->getDiagnostics())) {
+        if (!mTable->setSymbolStateAllowMangled(name, resId, symbol, mContext->getDiagnostics())) {
             return false;
         }
 
@@ -570,14 +568,17 @@
             source.line = util::deviceToHost32(sourceBlock->line);
         }
 
-        if (!mTable->addResourceAllowMangled(name, config, source, std::move(resourceValue),
+        resourceValue->setSource(source);
+        if (!mTable->addResourceAllowMangled(name, config, std::move(resourceValue),
                                              mContext->getDiagnostics())) {
             return false;
         }
 
         if ((entry->flags & ResTable_entry::FLAG_PUBLIC) != 0) {
-            if (!mTable->setSymbolStateAllowMangled(name, resId, mSource.withLine(0),
-                                                    SymbolState::kPublic,
+            Symbol symbol;
+            symbol.state = SymbolState::kPublic;
+            symbol.source = mSource.withLine(0);
+            if (!mTable->setSymbolStateAllowMangled(name, resId, symbol,
                                                     mContext->getDiagnostics())) {
                 return false;
             }
diff --git a/tools/aapt2/unflatten/BinaryResourceParser.h b/tools/aapt2/unflatten/BinaryResourceParser.h
index 4dbef5d..02c4081 100644
--- a/tools/aapt2/unflatten/BinaryResourceParser.h
+++ b/tools/aapt2/unflatten/BinaryResourceParser.h
@@ -66,26 +66,30 @@
     bool parseTypeSpec(const android::ResChunk_header* chunk);
     bool parseType(const ResourceTablePackage* package, const android::ResChunk_header* chunk);
 
-    std::unique_ptr<Item> parseValue(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::Res_value* value, uint16_t flags);
+    std::unique_ptr<Item> parseValue(const ResourceNameRef& name, const ConfigDescription& config,
+                                     const android::Res_value* value, uint16_t flags);
 
     std::unique_ptr<Value> parseMapEntry(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+                                         const ConfigDescription& config,
+                                         const android::ResTable_map_entry* map);
 
-    std::unique_ptr<Style> parseStyle(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+    std::unique_ptr<Style> parseStyle(const ResourceNameRef& name, const ConfigDescription& config,
+                                      const android::ResTable_map_entry* map);
 
     std::unique_ptr<Attribute> parseAttr(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+                                         const ConfigDescription& config,
+                                         const android::ResTable_map_entry* map);
 
-    std::unique_ptr<Array> parseArray(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+    std::unique_ptr<Array> parseArray(const ResourceNameRef& name, const ConfigDescription& config,
+                                      const android::ResTable_map_entry* map);
 
     std::unique_ptr<Plural> parsePlural(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+                                        const ConfigDescription& config,
+                                        const android::ResTable_map_entry* map);
 
     std::unique_ptr<Styleable> parseStyleable(const ResourceNameRef& name,
-            const ConfigDescription& config, const android::ResTable_map_entry* map);
+                                              const ConfigDescription& config,
+                                              const android::ResTable_map_entry* map);
 
     IAaptContext* mContext;
     ResourceTable* mTable;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java b/tools/aapt2/util/Comparators.h
similarity index 62%
copy from packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
copy to tools/aapt2/util/Comparators.h
index 6769716..652018e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/StringLruCache.java
+++ b/tools/aapt2/util/Comparators.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -14,13 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.recents.model;
+#ifndef AAPT_UTIL_COMPARATORS_H
+#define AAPT_UTIL_COMPARATORS_H
 
-/**
- * The String LRU cache.
- */
-class StringLruCache extends KeyStoreLruCache<String> {
-    public StringLruCache(int cacheSize) {
-        super(cacheSize);
-    }
-}
\ No newline at end of file
+namespace aapt {
+namespace cmp {
+
+inline bool lessThan(const ResourceConfigValue& a, const ConfigDescription& b) {
+    return a.config < b;
+}
+
+} // namespace cmp
+} // namespace aapt
+
+#endif /* AAPT_UTIL_COMPARATORS_H */
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 0da6bb6..007d075 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -242,7 +242,7 @@
 
     @Override
     public void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback callback, boolean scaleUp) {
+            IRemoteCallback callback0, IRemoteCallback callback1, boolean scaleUp) {
         // TODO Auto-generated method stub
     }
 
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.aidl b/wifi/java/android/net/wifi/BatchedScanResult.aidl
deleted file mode 100644
index a70bc0a..0000000
--- a/wifi/java/android/net/wifi/BatchedScanResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2013, 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.net.wifi;
-
-parcelable BatchedScanResult;
diff --git a/wifi/java/android/net/wifi/BatchedScanResult.java b/wifi/java/android/net/wifi/BatchedScanResult.java
index 7598b92..5bafdd8 100644
--- a/wifi/java/android/net/wifi/BatchedScanResult.java
+++ b/wifi/java/android/net/wifi/BatchedScanResult.java
@@ -25,8 +25,9 @@
 /**
  * Describes the Results of a batched set of wifi scans where the firmware performs many
  * scans and stores the timestamped results without waking the main processor each time.
- * @hide pending review
+ * @hide
  */
+@Deprecated
 public class BatchedScanResult implements Parcelable {
     private static final String TAG = "BatchedScanResult";
 
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.aidl b/wifi/java/android/net/wifi/BatchedScanSettings.aidl
deleted file mode 100644
index 8cfc508..0000000
--- a/wifi/java/android/net/wifi/BatchedScanSettings.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2013, 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.net.wifi;
-
-parcelable BatchedScanSettings;
diff --git a/wifi/java/android/net/wifi/BatchedScanSettings.java b/wifi/java/android/net/wifi/BatchedScanSettings.java
deleted file mode 100644
index 54801ad..0000000
--- a/wifi/java/android/net/wifi/BatchedScanSettings.java
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2008 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.net.wifi;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * Describes the settings for batched wifi scans where the firmware performs many
- * scans and stores the timestamped results without waking the main processor each time.
- * This can give information over time with minimal battery impact.
- * @hide pending review
- */
-public class BatchedScanSettings implements Parcelable {
-    private static final String TAG = "BatchedScanSettings";
-
-    /** Used to indicate no preference for an int value */
-    public final static int UNSPECIFIED = Integer.MAX_VALUE;
-
-    // TODO - make MIN/mAX as standard for wifi batch capability requirement.
-    public final static int MIN_SCANS_PER_BATCH = 2;
-    public final static int MAX_SCANS_PER_BATCH = 20;
-    public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
-
-    public final static int MIN_AP_PER_SCAN = 2;
-    public final static int MAX_AP_PER_SCAN = 16;
-    public final static int DEFAULT_AP_PER_SCAN = 16;
-
-    public final static int MIN_INTERVAL_SEC = 10;
-    public final static int MAX_INTERVAL_SEC = 500;
-    public final static int DEFAULT_INTERVAL_SEC = 30;
-
-    public final static int MIN_AP_FOR_DISTANCE = 0;
-    public final static int MAX_AP_FOR_DISTANCE = MAX_AP_PER_SCAN;
-    public final static int DEFAULT_AP_FOR_DISTANCE = 0;
-
-    public final static int MAX_WIFI_CHANNEL = 196;
-
-    /** The expected number of scans per batch.  Note that the firmware may drop scans
-     *  leading to fewer scans during the normal batch scan duration.  This value need not
-     *  be specified (may be set to {@link UNSPECIFIED}) by the application and we will try
-     *  to scan as many times as the firmware can support.  If another app requests fewer
-     *  scans per batch we will attempt to honor that.
-     */
-    public int maxScansPerBatch;
-
-    /** The maximum desired AP listed per scan.  Fewer AP may be returned if that's all
-     *  that the driver detected.  If another application requests more AP per scan that
-     *  will take precedence.  The if more channels are detected than we request, the APs
-     *  with the lowest signal strength will be dropped.
-     */
-    public int maxApPerScan;
-
-    /** The channels used in the scan.  If all channels should be used, {@code null} may be
-     *  specified.  If another application requests more channels or all channels, that
-     *  will take precedence.
-     */
-    public Collection<String> channelSet;
-
-    /** The time between the start of two sequential scans, in seconds.  If another
-     *  application requests more frequent scans, that will take precedence.  If this
-     * value is less than the duration of a scan, the next scan should start immediately.
-     */
-    public int scanIntervalSec;
-
-    /** The number of the best (strongest signal) APs for which the firmware will
-     *  attempt to get distance information (RTT).  Not all firmware supports this
-     *  feature, so it may be ignored.  If another application requests a greater
-     *  number, that will take precedence.
-     */
-    public int maxApForDistance;
-
-    public BatchedScanSettings() {
-        clear();
-    }
-
-    public void clear() {
-        maxScansPerBatch = UNSPECIFIED;
-        maxApPerScan = UNSPECIFIED;
-        channelSet = null;
-        scanIntervalSec = UNSPECIFIED;
-        maxApForDistance = UNSPECIFIED;
-    }
-
-    public BatchedScanSettings(BatchedScanSettings source) {
-        maxScansPerBatch = source.maxScansPerBatch;
-        maxApPerScan = source.maxApPerScan;
-        if (source.channelSet != null) {
-            channelSet = new ArrayList(source.channelSet);
-        }
-        scanIntervalSec = source.scanIntervalSec;
-        maxApForDistance = source.maxApForDistance;
-    }
-
-    private boolean channelSetIsValid() {
-        if (channelSet == null || channelSet.isEmpty()) return true;
-        for (String channel : channelSet) {
-            try {
-                int i = Integer.parseInt(channel);
-                if (i > 0 && i <= MAX_WIFI_CHANNEL) continue;
-            } catch (NumberFormatException e) {}
-            if (channel.equals("A") || channel.equals("B")) continue;
-            return false;
-        }
-        return true;
-    }
-    /** @hide */
-    public boolean isInvalid() {
-        if (maxScansPerBatch != UNSPECIFIED && (maxScansPerBatch < MIN_SCANS_PER_BATCH ||
-                maxScansPerBatch > MAX_SCANS_PER_BATCH)) return true;
-        if (maxApPerScan != UNSPECIFIED && (maxApPerScan < MIN_AP_PER_SCAN ||
-                maxApPerScan > MAX_AP_PER_SCAN)) return true;
-        if (channelSetIsValid() == false) return true;
-        if (scanIntervalSec != UNSPECIFIED && (scanIntervalSec < MIN_INTERVAL_SEC ||
-                scanIntervalSec > MAX_INTERVAL_SEC)) return true;
-        if (maxApForDistance != UNSPECIFIED && (maxApForDistance < MIN_AP_FOR_DISTANCE ||
-                maxApForDistance > MAX_AP_FOR_DISTANCE)) return true;
-        return false;
-    }
-
-    /** @hide */
-    public void constrain() {
-        if (scanIntervalSec == UNSPECIFIED) {
-            scanIntervalSec = DEFAULT_INTERVAL_SEC;
-        } else if (scanIntervalSec < MIN_INTERVAL_SEC) {
-            scanIntervalSec = MIN_INTERVAL_SEC;
-        } else if (scanIntervalSec > MAX_INTERVAL_SEC) {
-            scanIntervalSec = MAX_INTERVAL_SEC;
-        }
-
-        if (maxScansPerBatch == UNSPECIFIED) {
-            maxScansPerBatch = DEFAULT_SCANS_PER_BATCH;
-        } else if (maxScansPerBatch < MIN_SCANS_PER_BATCH) {
-            maxScansPerBatch = MIN_SCANS_PER_BATCH;
-        } else if (maxScansPerBatch > MAX_SCANS_PER_BATCH) {
-            maxScansPerBatch = MAX_SCANS_PER_BATCH;
-        }
-
-        if (maxApPerScan == UNSPECIFIED) {
-            maxApPerScan = DEFAULT_AP_PER_SCAN;
-        } else if (maxApPerScan < MIN_AP_PER_SCAN) {
-            maxApPerScan = MIN_AP_PER_SCAN;
-        } else if (maxApPerScan > MAX_AP_PER_SCAN) {
-            maxApPerScan = MAX_AP_PER_SCAN;
-        }
-
-        if (maxApForDistance == UNSPECIFIED) {
-            maxApForDistance = DEFAULT_AP_FOR_DISTANCE;
-        } else if (maxApForDistance < MIN_AP_FOR_DISTANCE) {
-            maxApForDistance = MIN_AP_FOR_DISTANCE;
-        } else if (maxApForDistance > MAX_AP_FOR_DISTANCE) {
-            maxApForDistance = MAX_AP_FOR_DISTANCE;
-        }
-    }
-
-
-    @Override
-    public boolean equals(Object obj) {
-        if (obj instanceof BatchedScanSettings == false) return false;
-        BatchedScanSettings o = (BatchedScanSettings)obj;
-        if (maxScansPerBatch != o.maxScansPerBatch ||
-              maxApPerScan != o.maxApPerScan ||
-              scanIntervalSec != o.scanIntervalSec ||
-              maxApForDistance != o.maxApForDistance) return false;
-        if (channelSet == null) {
-            return (o.channelSet == null);
-        }
-        return channelSet.equals(o.channelSet);
-    }
-
-    @Override
-    public int hashCode() {
-        return maxScansPerBatch +
-                (maxApPerScan * 3) +
-                (scanIntervalSec * 5) +
-                (maxApForDistance * 7) +
-                (channelSet.hashCode() * 11);
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        String none = "<none>";
-
-        sb.append("BatchScanSettings [maxScansPerBatch: ").
-                append(maxScansPerBatch == UNSPECIFIED ? none : maxScansPerBatch).
-                append(", maxApPerScan: ").append(maxApPerScan == UNSPECIFIED? none : maxApPerScan).
-                append(", scanIntervalSec: ").
-                append(scanIntervalSec == UNSPECIFIED ? none : scanIntervalSec).
-                append(", maxApForDistance: ").
-                append(maxApForDistance == UNSPECIFIED ? none : maxApForDistance).
-                append(", channelSet: ");
-        if (channelSet == null) {
-            sb.append("ALL");
-        } else {
-            sb.append("<");
-            for (String channel : channelSet) {
-                sb.append(" " + channel);
-            }
-            sb.append(">");
-        }
-        sb.append("]");
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(maxScansPerBatch);
-        dest.writeInt(maxApPerScan);
-        dest.writeInt(scanIntervalSec);
-        dest.writeInt(maxApForDistance);
-        dest.writeInt(channelSet == null ? 0 : channelSet.size());
-        if (channelSet != null) {
-            for (String channel : channelSet) dest.writeString(channel);
-        }
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<BatchedScanSettings> CREATOR =
-        new Creator<BatchedScanSettings>() {
-            public BatchedScanSettings createFromParcel(Parcel in) {
-                BatchedScanSettings settings = new BatchedScanSettings();
-                settings.maxScansPerBatch = in.readInt();
-                settings.maxApPerScan = in.readInt();
-                settings.scanIntervalSec = in.readInt();
-                settings.maxApForDistance = in.readInt();
-                int channelCount = in.readInt();
-                if (channelCount > 0) {
-                    settings.channelSet = new ArrayList(channelCount);
-                    while (channelCount-- > 0) {
-                        settings.channelSet.add(in.readString());
-                    }
-                }
-                return settings;
-            }
-
-            public BatchedScanSettings[] newArray(int size) {
-                return new BatchedScanSettings[size];
-            }
-        };
-}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 23be8e0..bad4e9c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -16,12 +16,9 @@
 
 package android.net.wifi;
 
-import android.net.wifi.BatchedScanResult;
-import android.net.wifi.BatchedScanSettings;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.ScanSettings;
-import android.net.wifi.WifiChannel;
 import android.net.wifi.ScanResult;
 import android.net.wifi.ScanInfo;
 import android.net.wifi.WifiConnectionStatistics;
@@ -61,12 +58,8 @@
 
     boolean pingSupplicant();
 
-    List<WifiChannel> getChannelList();
-
     void startScan(in ScanSettings requested, in WorkSource ws);
 
-    void startLocationRestrictedScan(in WorkSource ws);
-
     List<ScanResult> getScanResults(String callingPackage);
 
     void disconnect();
@@ -125,10 +118,6 @@
 
     void setWifiApConfiguration(in WifiConfiguration wifiConfig);
 
-    void startWifi();
-
-    void stopWifi();
-
     void addToBlacklist(String bssid);
 
     void clearBlacklist();
@@ -141,16 +130,6 @@
 
     void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
 
-    boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder, in WorkSource ws);
-
-    void stopBatchedScan(in BatchedScanSettings requested);
-
-    List<BatchedScanResult> getBatchedScanResults(String callingPackage);
-
-    boolean isBatchedScanSupported();
-
-    void pollBatchedScan();
-
     String getWpsNfcConfigurationToken(int netId);
 
     void enableVerboseLogging(int verbose);
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 8a20012..dc06789 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -309,6 +309,15 @@
      * @hide
      */
     public static class InformationElement {
+        public static final int EID_SSID = 0;
+        public static final int EID_BSS_LOAD = 11;
+        public static final int EID_HT_OPERATION = 61;
+        public static final int EID_INTERWORKING = 107;
+        public static final int EID_ROAMING_CONSORTIUM = 111;
+        public static final int EID_EXTENDED_CAPS = 127;
+        public static final int EID_VHT_OPERATION = 192;
+        public static final int EID_VSA = 221;
+
         public int id;
         public byte[] bytes;
 
diff --git a/wifi/java/android/net/wifi/WifiChannel.aidl b/wifi/java/android/net/wifi/WifiChannel.aidl
deleted file mode 100644
index c3d06bd..0000000
--- a/wifi/java/android/net/wifi/WifiChannel.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi;
-
-parcelable WifiChannel;
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ff8d6d4d..bd030e8 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -27,7 +27,6 @@
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.wifi.ScanSettings;
-import android.net.wifi.WifiChannel;
 import android.os.Binder;
 import android.os.Build;
 import android.os.IBinder;
@@ -440,8 +439,11 @@
     /**
      * A batch of access point scans has been completed and the results areavailable.
      * Call {@link #getBatchedScanResults()} to obtain the results.
-     * @hide pending review
+     * @deprecated This API is nolonger supported.
+     * Use {@link android.net.wifi.WifiScanner} API
+     * @hide
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
             "android.net.wifi.BATCHED_RESULTS";
@@ -904,22 +906,6 @@
         }
     }
 
-    /**
-     * Get a list of available channels for customized scan.
-     *
-     * @see {@link WifiChannel}
-     *
-     * @return the channel list, or null if not available
-     * @hide
-     */
-    public List<WifiChannel> getChannelList() {
-        try {
-            return mService.getChannelList();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
     /* Keep this list in sync with wifi_hal.h */
     /** @hide */
     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
@@ -1086,17 +1072,8 @@
     public WifiActivityEnergyInfo getControllerActivityEnergyInfo(int updateType) {
         if (mService == null) return null;
         try {
-            WifiActivityEnergyInfo record;
-            if (!isEnhancedPowerReportingSupported()) {
-                return null;
-            }
             synchronized(this) {
-                record = mService.reportActivityInfo();
-                if (record != null && record.isValid()) {
-                    return record;
-                } else {
-                    return null;
-                }
+                return mService.reportActivityInfo();
             }
         } catch (RemoteException e) {
             Log.e(TAG, "getControllerActivityEnergyInfo: " + e);
@@ -1134,142 +1111,41 @@
      * startLocationRestrictedScan()
      * Trigger a scan which will not make use of DFS channels and is thus not suitable for
      * establishing wifi connection.
+     * @deprecated This API is nolonger supported.
+     * Use {@link android.net.wifi.WifiScanner} API
      * @hide
      */
+    @Deprecated
     @SystemApi
     public boolean startLocationRestrictedScan(WorkSource workSource) {
-        try {
-            mService.startLocationRestrictedScan(workSource);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Request a scan for access points in specified channel list. Each channel is specified by its
-     * frequency in MHz, e.g. "5500" (do NOT include "DFS" even though it is). The availability of
-     * the results is made known later in the same way as {@link #startScan}.
-     *
-     * Note:
-     *
-     * 1. Customized scan is for non-connection purposes, i.e. it won't trigger a wifi connection
-     *    even though it finds some known networks.
-     *
-     * 2. Customized scan result may include access points that is not specified in the channel
-     *    list. An app will need to do frequency filtering if it wants to get pure results for the
-     *    channel list it specified.
-     *
-     * @hide
-     */
-    public boolean startCustomizedScan(ScanSettings requested) {
-        try {
-            mService.startScan(requested, null);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /** @hide */
-    public boolean startCustomizedScan(ScanSettings requested, WorkSource workSource) {
-        try {
-            mService.startScan(requested, workSource);
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Request a batched scan for access points.  To end your requested batched scan,
-     * call stopBatchedScan with the same Settings.
-     *
-     * If there are mulitple requests for batched scans, the more demanding settings will
-     * take precidence.
-     *
-     * @param requested {@link BatchedScanSettings} the scan settings requested.
-     * @return false on known error
-     * @hide
-     */
-    public boolean requestBatchedScan(BatchedScanSettings requested) {
-        try {
-            return mService.requestBatchedScan(requested, new Binder(), null);
-        } catch (RemoteException e) { return false; }
-    }
-    /** @hide */
-    public boolean requestBatchedScan(BatchedScanSettings requested, WorkSource workSource) {
-        try {
-            return mService.requestBatchedScan(requested, new Binder(), workSource);
-        } catch (RemoteException e) { return false; }
+        return false;
     }
 
     /**
      * Check if the Batched Scan feature is supported.
      *
      * @return false if not supported.
+     * @deprecated This API is nolonger supported.
+     * Use {@link android.net.wifi.WifiScanner} API
      * @hide
      */
+    @Deprecated
     @SystemApi
     public boolean isBatchedScanSupported() {
-        try {
-            return mService.isBatchedScanSupported();
-        } catch (RemoteException e) { return false; }
-    }
-
-    /**
-     * End a requested batch scan for this applicaiton.  Note that batched scan may
-     * still occur if other apps are using them.
-     *
-     * @param requested {@link BatchedScanSettings} the scan settings you previously requested
-     *        and now wish to stop.  A value of null here will stop all scans requested by the
-     *        calling App.
-     * @hide
-     */
-    public void stopBatchedScan(BatchedScanSettings requested) {
-        try {
-            mService.stopBatchedScan(requested);
-        } catch (RemoteException e) {}
+        return false;
     }
 
     /**
      * Retrieve the latest batched scan result.  This should be called immediately after
      * {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
+     * @deprecated This API is nolonger supported.
+     * Use {@link android.net.wifi.WifiScanner} API
      * @hide
      */
+    @Deprecated
     @SystemApi
     public List<BatchedScanResult> getBatchedScanResults() {
-        try {
-            return mService.getBatchedScanResults(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Force a re-reading of batched scan results.  This will attempt
-     * to read more information from the chip, but will do so at the expense
-     * of previous data.  Rate limited to the current scan frequency.
-     *
-     * pollBatchedScan will always wait 1 period from the start of the batch
-     * before trying to read from the chip, so if your #scans/batch == 1 this will
-     * have no effect.
-     *
-     * If you had already waited 1 period before calling, this should have
-     * immediate (though async) effect.
-     *
-     * If you call before that 1 period is up this will set up a timer and fetch
-     * results when the 1 period is up.
-     *
-     * Servicing a pollBatchedScan request (immediate or after timed delay) starts a
-     * new batch, so if you were doing 10 scans/batch and called in the 4th scan, you
-     * would get data in the 4th and then again 10 scans later.
-     * @hide
-     */
-    public void pollBatchedScan() {
-        try {
-            mService.pollBatchedScan();
-        } catch (RemoteException e) { }
+        return null;
     }
 
     /**
@@ -1634,48 +1510,6 @@
         }
     }
 
-   /**
-     * Start the driver and connect to network.
-     *
-     * This function will over-ride WifiLock and device idle status. For example,
-     * even if the device is idle or there is only a scan-only lock held,
-     * a start wifi would mean that wifi connection is kept active until
-     * a stopWifi() is sent.
-     *
-     * This API is used by WifiStateTracker
-     *
-     * @return {@code true} if the operation succeeds else {@code false}
-     * @hide
-     */
-    public boolean startWifi() {
-        try {
-            mService.startWifi();
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Disconnect from a network (if any) and stop the driver.
-     *
-     * This function will over-ride WifiLock and device idle status. Wi-Fi
-     * stays inactive until a startWifi() is issued.
-     *
-     * This API is used by WifiStateTracker
-     *
-     * @return {@code true} if the operation succeeds else {@code false}
-     * @hide
-     */
-    public boolean stopWifi() {
-        try {
-            mService.stopWifi();
-            return true;
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
     /**
      * Add a bssid to the supplicant blacklist
      *
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index a65f250..c26ca6e 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -709,6 +709,7 @@
         validateChannel();
         HotlistSettings settings = new HotlistSettings();
         settings.bssidInfos = bssidInfos;
+        settings.apLostThreshold = apLostThreshold;
         sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
     }